Renamed OpenGroupAPIV2 to OpenGroupAPI

Added the inbox endpoints
This commit is contained in:
Morgan Pretty 2022-02-15 16:30:11 +11:00
parent 4963a84ddd
commit 63e6cdd9ec
53 changed files with 490 additions and 392 deletions

View file

@ -233,7 +233,7 @@
B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A62398B23E00211ABE /* QRCodeVC.swift */; }; B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A62398B23E00211ABE /* QRCodeVC.swift */; };
B886B4A92398BA1500211ABE /* QRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A82398BA1500211ABE /* QRCode.swift */; }; B886B4A92398BA1500211ABE /* QRCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A82398BA1500211ABE /* QRCode.swift */; };
B88A1AC725C90A4700E6D421 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; }; B88A1AC725C90A4700E6D421 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; };
B88FA7B826045D100049422F /* OpenGroupAPIV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7B726045D100049422F /* OpenGroupAPIV2.swift */; }; B88FA7B826045D100049422F /* OpenGroupAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7B726045D100049422F /* OpenGroupAPI.swift */; };
B88FA7F2260C3EB10049422F /* OpenGroupSuggestionGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7F1260C3EB10049422F /* OpenGroupSuggestionGrid.swift */; }; B88FA7F2260C3EB10049422F /* OpenGroupSuggestionGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7F1260C3EB10049422F /* OpenGroupSuggestionGrid.swift */; };
B88FA7FB26114EA70049422F /* Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7FA26114EA70049422F /* Hex.swift */; }; B88FA7FB26114EA70049422F /* Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = B88FA7FA26114EA70049422F /* Hex.swift */; };
B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; }; B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; };
@ -754,7 +754,7 @@
C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.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 /* OpenGroupAPI+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66CB260AF1F3001EFC55 /* OpenGroupAPI+ObjC.swift */; };
C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; };
C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; };
C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; }; C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ECBF7A257056B700EA7FCE /* Threading.swift */; };
@ -844,6 +844,8 @@
FDC438BD27BB2AB400C60D73 /* Mockable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438BC27BB2AB400C60D73 /* Mockable.swift */; }; FDC438BD27BB2AB400C60D73 /* Mockable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438BC27BB2AB400C60D73 /* Mockable.swift */; };
FDC438C127BB4E6800C60D73 /* Dependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438C027BB4E6800C60D73 /* Dependencies.swift */; }; FDC438C127BB4E6800C60D73 /* Dependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438C027BB4E6800C60D73 /* Dependencies.swift */; };
FDC438C327BB512200C60D73 /* SodiumProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438C227BB512200C60D73 /* SodiumProtocols.swift */; }; FDC438C327BB512200C60D73 /* SodiumProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438C227BB512200C60D73 /* SodiumProtocols.swift */; };
FDC438C727BB6DF000C60D73 /* DirectMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438C627BB6DF000C60D73 /* DirectMessage.swift */; };
FDC438C927BB706500C60D73 /* SendDirectMessageRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438C827BB706500C60D73 /* SendDirectMessageRequest.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -1323,7 +1325,7 @@
B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = "<group>"; }; B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = "<group>"; };
B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = "<group>"; }; B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = "<group>"; };
B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = "<group>"; }; B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = "<group>"; };
B88FA7B726045D100049422F /* OpenGroupAPIV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIV2.swift; sourceTree = "<group>"; }; B88FA7B726045D100049422F /* OpenGroupAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPI.swift; sourceTree = "<group>"; };
B88FA7F1260C3EB10049422F /* OpenGroupSuggestionGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupSuggestionGrid.swift; sourceTree = "<group>"; }; B88FA7F1260C3EB10049422F /* OpenGroupSuggestionGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupSuggestionGrid.swift; sourceTree = "<group>"; };
B88FA7FA26114EA70049422F /* Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hex.swift; sourceTree = "<group>"; }; B88FA7FA26114EA70049422F /* Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hex.swift; sourceTree = "<group>"; };
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>"; };
@ -1859,7 +1861,7 @@
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>"; };
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 /* OpenGroupAPI+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupAPI+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+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Utilities.swift"; sourceTree = "<group>"; }; C3E7134E251C867C009649BB /* Sodium+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Utilities.swift"; sourceTree = "<group>"; };
@ -1974,6 +1976,8 @@
FDC438BC27BB2AB400C60D73 /* Mockable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mockable.swift; sourceTree = "<group>"; }; FDC438BC27BB2AB400C60D73 /* Mockable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mockable.swift; sourceTree = "<group>"; };
FDC438C027BB4E6800C60D73 /* Dependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dependencies.swift; sourceTree = "<group>"; }; FDC438C027BB4E6800C60D73 /* Dependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dependencies.swift; sourceTree = "<group>"; };
FDC438C227BB512200C60D73 /* SodiumProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SodiumProtocols.swift; sourceTree = "<group>"; }; FDC438C227BB512200C60D73 /* SodiumProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SodiumProtocols.swift; sourceTree = "<group>"; };
FDC438C627BB6DF000C60D73 /* DirectMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectMessage.swift; sourceTree = "<group>"; };
FDC438C827BB706500C60D73 /* SendDirectMessageRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendDirectMessageRequest.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 */
@ -3351,8 +3355,8 @@
children = ( children = (
FDC4381827B34EAD00C60D73 /* Models */, FDC4381827B34EAD00C60D73 /* Models */,
FDC4380727B31D3A00C60D73 /* Types */, FDC4380727B31D3A00C60D73 /* Types */,
B88FA7B726045D100049422F /* OpenGroupAPIV2.swift */, B88FA7B726045D100049422F /* OpenGroupAPI.swift */,
C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */, C3DB66CB260AF1F3001EFC55 /* OpenGroupAPI+ObjC.swift */,
C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */, C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */,
); );
path = "Open Groups"; path = "Open Groups";
@ -3834,12 +3838,15 @@
FDC4384B27B47F7700C60D73 /* OpenGroupV2.swift */, FDC4384B27B47F7700C60D73 /* OpenGroupV2.swift */,
FDC4381B27B354AC00C60D73 /* PublicKeyBody.swift */, FDC4381B27B354AC00C60D73 /* PublicKeyBody.swift */,
FDC4386A27B4E88F00C60D73 /* BatchRequestInfo.swift */, FDC4386A27B4E88F00C60D73 /* BatchRequestInfo.swift */,
FDC4386627B4E10E00C60D73 /* Capabilities.swift */,
FDC4385C27B4C18900C60D73 /* Room.swift */, FDC4385C27B4C18900C60D73 /* Room.swift */,
FDC4386427B4DE7600C60D73 /* RoomPollInfo.swift */, FDC4386427B4DE7600C60D73 /* RoomPollInfo.swift */,
FDC4385E27B4C4A200C60D73 /* PinnedMessage.swift */, FDC4385E27B4C4A200C60D73 /* PinnedMessage.swift */,
FDC4386027B4CDDF00C60D73 /* FileResponse.swift */, FDC4386027B4CDDF00C60D73 /* FileResponse.swift */,
FDC4387727B5C35400C60D73 /* SendMessageRequest.swift */, FDC4387727B5C35400C60D73 /* SendMessageRequest.swift */,
FDC4386227B4D94E00C60D73 /* OGMessage.swift */, FDC4386227B4D94E00C60D73 /* OGMessage.swift */,
FDC438C627BB6DF000C60D73 /* DirectMessage.swift */,
FDC438C827BB706500C60D73 /* SendDirectMessageRequest.swift */,
FDC438A327BB107F00C60D73 /* UserBanRequest.swift */, FDC438A327BB107F00C60D73 /* UserBanRequest.swift */,
FDC438A527BB113A00C60D73 /* UserUnbanRequest.swift */, FDC438A527BB113A00C60D73 /* UserUnbanRequest.swift */,
FDC438A727BB11CD00C60D73 /* UserPermissionsRequest.swift */, FDC438A727BB11CD00C60D73 /* UserPermissionsRequest.swift */,
@ -3849,7 +3856,6 @@
FDC4382B27B380E300C60D73 /* MemberCountResponse.swift */, FDC4382B27B380E300C60D73 /* MemberCountResponse.swift */,
FDC4382527B37F6900C60D73 /* DeletedMessagesResponse.swift */, FDC4382527B37F6900C60D73 /* DeletedMessagesResponse.swift */,
FDC4384627B47F4D00C60D73 /* Deletion.swift */, FDC4384627B47F4D00C60D73 /* Deletion.swift */,
FDC4386627B4E10E00C60D73 /* Capabilities.swift */,
FDC4382727B37FD300C60D73 /* ModeratorsResponse.swift */, FDC4382727B37FD300C60D73 /* ModeratorsResponse.swift */,
FDC4381927B34EBA00C60D73 /* LegacyCompactPollBody.swift */, FDC4381927B34EBA00C60D73 /* LegacyCompactPollBody.swift */,
FDC4384527B47F4D00C60D73 /* LegacyCompactPollResponse.swift */, FDC4384527B47F4D00C60D73 /* LegacyCompactPollResponse.swift */,
@ -5163,6 +5169,7 @@
FDC4385927B484E800C60D73 /* FileUploadBody.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 */,
FDC438C727BB6DF000C60D73 /* DirectMessage.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 */,
@ -5194,13 +5201,14 @@
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */, C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */,
FDC4380927B31D4E00C60D73 /* Error.swift in Sources */, FDC4380927B31D4E00C60D73 /* Error.swift in Sources */,
FDC4382027B36ADC00C60D73 /* Endpoint.swift in Sources */, FDC4382027B36ADC00C60D73 /* Endpoint.swift in Sources */,
C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */, C3DB66CC260AF1F3001EFC55 /* OpenGroupAPI+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 */, FDC4384C27B47F7700C60D73 /* OpenGroupV2.swift in Sources */,
FDC4382627B37F6900C60D73 /* DeletedMessagesResponse.swift in Sources */, FDC4382627B37F6900C60D73 /* DeletedMessagesResponse.swift in Sources */,
B88FA7B826045D100049422F /* OpenGroupAPIV2.swift in Sources */, B88FA7B826045D100049422F /* OpenGroupAPI.swift in Sources */,
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */, C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */,
FDC438C927BB706500C60D73 /* SendDirectMessageRequest.swift in Sources */,
C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */, C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */,
C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */, C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */,
B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */, B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */,

View file

@ -700,7 +700,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
let publicKey = message.authorId let publicKey = message.authorId
guard let openGroupV2 = Storage.shared.getV2OpenGroup(for: threadID) else { return } guard let openGroupV2 = Storage.shared.getV2OpenGroup(for: threadID) else { return }
OpenGroupAPIV2.legacyBan(publicKey, from: openGroupV2.room, on: openGroupV2.server).retainUntilComplete() OpenGroupAPI.legacyBan(publicKey, from: openGroupV2.room, on: openGroupV2.server).retainUntilComplete()
})) }))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)
@ -714,7 +714,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
let publicKey = message.authorId let publicKey = message.authorId
guard let openGroupV2 = Storage.shared.getV2OpenGroup(for: threadID) else { return } guard let openGroupV2 = Storage.shared.getV2OpenGroup(for: threadID) else { return }
OpenGroupAPIV2.legacyBanAndDeleteAllMessages(publicKey, from: openGroupV2.room, on: openGroupV2.server).retainUntilComplete() OpenGroupAPI.legacyBanAndDeleteAllMessages(publicKey, from: openGroupV2.room, on: openGroupV2.server).retainUntilComplete()
})) }))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil)) alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
present(alert, animated: true, completion: nil) present(alert, animated: true, completion: nil)

View file

@ -373,7 +373,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
// Update member count if this is a V2 open group // Update member count if this is a V2 open group
// TODO: Non-legacy version (I assue this comes through room updates... 'activeUsers'? // TODO: Non-legacy version (I assue this comes through room updates... 'activeUsers'?
if let v2OpenGroup = Storage.shared.getV2OpenGroup(for: thread.uniqueId!) { if let v2OpenGroup = Storage.shared.getV2OpenGroup(for: thread.uniqueId!) {
OpenGroupAPIV2.legacyGetMemberCount(for: v2OpenGroup.room, on: v2OpenGroup.server).retainUntilComplete() OpenGroupAPI.legacyGetMemberCount(for: v2OpenGroup.room, on: v2OpenGroup.server).retainUntilComplete()
} }
} }

View file

@ -1006,11 +1006,11 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
// If it's an incoming message the user must have moderator status // If it's an incoming message the user must have moderator status
if (self.interaction.interactionType == OWSInteractionType_IncomingMessage) { if (self.interaction.interactionType == OWSInteractionType_IncomingMessage) {
NSString *userPublicKey = [LKStorage.shared getUserPublicKey]; NSString *userPublicKey = [LKStorage.shared getUserPublicKey];
if (![SNOpenGroupAPIV2 isUserModerator:userPublicKey forRoom:openGroupV2.room onServer:openGroupV2.server]) { return; } if (![SNOpenGroupAPI isUserModerator:userPublicKey forRoom:openGroupV2.room onServer:openGroupV2.server]) { return; }
} }
// Delete the message // Delete the message
[[SNOpenGroupAPIV2 deleteMessageWithServerID:message.openGroupServerMessageID fromRoom:openGroupV2.room onServer:openGroupV2.server].catch(^(NSError *error) { [[SNOpenGroupAPI deleteMessageWithServerID:message.openGroupServerMessageID fromRoom:openGroupV2.room onServer:openGroupV2.server].catch(^(NSError *error) {
// Roll back // Roll back
[self.interaction save]; [self.interaction save];
}) retainUntilComplete]; }) retainUntilComplete];
@ -1060,14 +1060,14 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
if (self.interaction.interactionType == OWSInteractionType_IncomingMessage) { if (self.interaction.interactionType == OWSInteractionType_IncomingMessage) {
NSString *userPublicKey = [LKStorage.shared getUserPublicKey]; NSString *userPublicKey = [LKStorage.shared getUserPublicKey];
if (openGroupV2 != nil) { if (openGroupV2 != nil) {
if (![SNOpenGroupAPIV2 isUserModerator:userPublicKey forRoom:openGroupV2.room onServer:openGroupV2.server]) { return; } if (![SNOpenGroupAPI isUserModerator:userPublicKey forRoom:openGroupV2.room onServer:openGroupV2.server]) { return; }
} }
} }
// Delete the message // Delete the message
BOOL wasSentByUser = (interationType == OWSInteractionType_OutgoingMessage); BOOL wasSentByUser = (interationType == OWSInteractionType_OutgoingMessage);
if (openGroupV2 != nil) { if (openGroupV2 != nil) {
[[SNOpenGroupAPIV2 deleteMessageWithServerID:message.openGroupServerMessageID fromRoom:openGroupV2.room onServer:openGroupV2.server].catch(^(NSError *error) { [[SNOpenGroupAPI deleteMessageWithServerID:message.openGroupServerMessageID fromRoom:openGroupV2.room onServer:openGroupV2.server].catch(^(NSError *error) {
// Roll back // Roll back
[self.interaction save]; [self.interaction save];
}) retainUntilComplete]; }) retainUntilComplete];
@ -1133,7 +1133,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
if (interationType == OWSInteractionType_IncomingMessage) { if (interationType == OWSInteractionType_IncomingMessage) {
// Only allow deletion on incoming messages if the user has moderation permission // Only allow deletion on incoming messages if the user has moderation permission
if (openGroupV2 != nil) { if (openGroupV2 != nil) {
return [SNOpenGroupAPIV2 isUserModerator:[SNGeneralUtilities getUserPublicKey] forRoom:openGroupV2.room onServer:openGroupV2.server]; return [SNOpenGroupAPI isUserModerator:[SNGeneralUtilities getUserPublicKey] forRoom:openGroupV2.room onServer:openGroupV2.server];
} }
} else { } else {
return YES; return YES;
@ -1155,7 +1155,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
// Check that we're a moderator // Check that we're a moderator
if (openGroupV2 != nil) { if (openGroupV2 != nil) {
return [SNOpenGroupAPIV2 isUserModerator:[SNGeneralUtilities getUserPublicKey] forRoom:openGroupV2.room onServer:openGroupV2.server]; return [SNOpenGroupAPI isUserModerator:[SNGeneralUtilities getUserPublicKey] forRoom:openGroupV2.room onServer:openGroupV2.server];
} }
} }

View file

@ -163,7 +163,7 @@ private extension MentionSelectionView {
profilePictureView.publicKey = mentionCandidate.publicKey profilePictureView.publicKey = mentionCandidate.publicKey
profilePictureView.update() profilePictureView.update()
if let server = openGroupServer, let room = openGroupRoom { if let server = openGroupServer, let room = openGroupRoom {
let isUserModerator = OpenGroupAPIV2.isUserModerator(mentionCandidate.publicKey, for: room, on: server) let isUserModerator = OpenGroupAPI.isUserModerator(mentionCandidate.publicKey, for: room, on: server)
moderatorIconImageView.isHidden = !isUserModerator moderatorIconImageView.isHidden = !isUserModerator
} else { } else {
moderatorIconImageView.isHidden = true moderatorIconImageView.isHidden = true

View file

@ -219,7 +219,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
} }
if let senderSessionID = senderSessionID, message.isOpenGroupMessage { if let senderSessionID = senderSessionID, message.isOpenGroupMessage {
if let openGroupV2 = Storage.shared.getV2OpenGroup(for: message.uniqueThreadId) { if let openGroupV2 = Storage.shared.getV2OpenGroup(for: message.uniqueThreadId) {
let isUserModerator = OpenGroupAPIV2.isUserModerator(senderSessionID, for: openGroupV2.room, on: openGroupV2.server) let isUserModerator = OpenGroupAPI.isUserModerator(senderSessionID, for: openGroupV2.room, on: openGroupV2.server)
moderatorIconImageView.isHidden = !isUserModerator || profilePictureView.isHidden moderatorIconImageView.isHidden = !isUserModerator || profilePictureView.isHidden
} else { } else {
moderatorIconImageView.isHidden = true moderatorIconImageView.isHidden = true

View file

@ -160,7 +160,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
let _ = IP2Country.shared.populateCacheIfNeeded() let _ = IP2Country.shared.populateCacheIfNeeded()
} }
// Get default open group rooms if needed // Get default open group rooms if needed
OpenGroupAPIV2.legacyGetDefaultRoomsIfNeeded() OpenGroupAPI.legacyGetDefaultRoomsIfNeeded()
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {

View file

@ -383,7 +383,7 @@ static NSTimeInterval launchStartedAt;
} }
if (CurrentAppContext().isMainApp) { if (CurrentAppContext().isMainApp) {
[SNOpenGroupAPIV2 legacyGetDefaultRoomsIfNeeded]; [SNOpenGroupAPI legacyGetDefaultRoomsIfNeeded];
} }
[[SNSnodeAPI getSnodePool] retainUntilComplete]; [[SNSnodeAPI getSnodePool] retainUntilComplete];

View file

@ -238,8 +238,8 @@ private final class EnterURLVC : UIViewController, UIGestureRecognizerDelegate,
return !suggestionGrid.frame.contains(location) return !suggestionGrid.frame.contains(location)
} }
func join(_ room: OpenGroupAPIV2.LegacyRoomInfo) { func join(_ room: OpenGroupAPI.LegacyRoomInfo) {
joinOpenGroupVC.joinV2OpenGroup(room: room.id, server: OpenGroupAPIV2.defaultServer, publicKey: OpenGroupAPIV2.defaultServerPublicKey) joinOpenGroupVC.joinV2OpenGroup(room: room.id, server: OpenGroupAPI.defaultServer, publicKey: OpenGroupAPI.defaultServerPublicKey)
} }
@objc private func joinOpenGroup() { @objc private func joinOpenGroup() {

View file

@ -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.LegacyRoomInfo] = [] { didSet { update() } } private var rooms: [OpenGroupAPI.LegacyRoomInfo] = [] { didSet { update() } }
private var heightConstraint: NSLayoutConstraint! private var heightConstraint: NSLayoutConstraint!
var delegate: OpenGroupSuggestionGridDelegate? var delegate: OpenGroupSuggestionGridDelegate?
@ -59,10 +59,10 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl
spinner.startAnimating() spinner.startAnimating()
heightConstraint = set(.height, to: OpenGroupSuggestionGrid.cellHeight) heightConstraint = set(.height, to: OpenGroupSuggestionGrid.cellHeight)
widthAnchor.constraint(greaterThanOrEqualToConstant: OpenGroupSuggestionGrid.cellHeight).isActive = true widthAnchor.constraint(greaterThanOrEqualToConstant: OpenGroupSuggestionGrid.cellHeight).isActive = true
if OpenGroupAPIV2.defaultRoomsPromise == nil { if OpenGroupAPI.defaultRoomsPromise == nil {
OpenGroupAPIV2.legacyGetDefaultRoomsIfNeeded() OpenGroupAPI.legacyGetDefaultRoomsIfNeeded()
} }
let _ = OpenGroupAPIV2.legacyDefaultRoomsPromise?.done { [weak self] rooms in let _ = OpenGroupAPI.legacyDefaultRoomsPromise?.done { [weak self] rooms in
// TODO: Update this for the new rooms API // TODO: Update this for the new rooms API
self?.rooms = rooms self?.rooms = rooms
} }
@ -105,7 +105,7 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl
extension OpenGroupSuggestionGrid { extension OpenGroupSuggestionGrid {
fileprivate final class Cell : UICollectionViewCell { fileprivate final class Cell : UICollectionViewCell {
var room: OpenGroupAPIV2.LegacyRoomInfo? { didSet { update() } } var room: OpenGroupAPI.LegacyRoomInfo? { didSet { update() } }
static let identifier = "OpenGroupSuggestionGridCell" static let identifier = "OpenGroupSuggestionGridCell"
@ -173,7 +173,7 @@ extension OpenGroupSuggestionGrid {
private func update() { private func update() {
guard let room = room else { return } guard let room = room else { return }
let promise = OpenGroupAPIV2.legacyGetGroupImage(for: room.id, on: OpenGroupAPIV2.defaultServer) let promise = OpenGroupAPI.legacyGetGroupImage(for: room.id, on: OpenGroupAPI.defaultServer)
imageView.image = given(promise.value) { UIImage(data: $0)! } imageView.image = given(promise.value) { UIImage(data: $0)! }
imageView.isHidden = (imageView.image == nil) imageView.isHidden = (imageView.image == nil)
label.text = room.name label.text = room.name
@ -184,5 +184,5 @@ extension OpenGroupSuggestionGrid {
// MARK: Delegate // MARK: Delegate
protocol OpenGroupSuggestionGridDelegate { protocol OpenGroupSuggestionGridDelegate {
func join(_ room: OpenGroupAPIV2.LegacyRoomInfo) func join(_ room: OpenGroupAPI.LegacyRoomInfo)
} }

View file

@ -102,7 +102,7 @@ public final class AttachmentDownloadJob : NSObject, Job, NSCoding { // NSObject
return handleFailure(Error.invalidURL) return handleFailure(Error.invalidURL)
} }
// TODO: Upgrade this to use the non-legacy version // TODO: Upgrade this to use the non-legacy version
OpenGroupAPIV2.legacyDownload(file, from: v2OpenGroup.room, on: v2OpenGroup.server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in OpenGroupAPI.legacyDownload(file, from: v2OpenGroup.room, on: v2OpenGroup.server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in
self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure) self.handleDownloadedAttachment(data: data, temporaryFilePath: temporaryFilePath, pointer: pointer, failureHandler: handleFailure)
}.catch(on: DispatchQueue.global()) { error in }.catch(on: DispatchQueue.global()) { error in
handleFailure(error) handleFailure(error)

View file

@ -73,7 +73,7 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N
stream, stream,
using: { data in using: { data in
// TODO: Upgrade this to use the non-legacy version // TODO: Upgrade this to use the non-legacy version
return OpenGroupAPIV2.legacyUpload(data, to: v2OpenGroup.room, on: v2OpenGroup.server) return OpenGroupAPI.legacyUpload(data, to: v2OpenGroup.room, on: v2OpenGroup.server)
}, },
encrypt: false, encrypt: false,
onSuccess: handleSuccess, onSuccess: handleSuccess,

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct AuthTokenResponse: Codable { struct AuthTokenResponse: Codable {
struct Challenge: Codable { struct Challenge: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
@ -20,7 +20,7 @@ extension OpenGroupAPIV2 {
// MARK: - Codable // MARK: - Codable
extension OpenGroupAPIV2.AuthTokenResponse.Challenge { extension OpenGroupAPI.AuthTokenResponse.Challenge {
init(from decoder: Decoder) throws { init(from decoder: Decoder) throws {
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self) let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
@ -28,10 +28,10 @@ extension OpenGroupAPIV2.AuthTokenResponse.Challenge {
let base64EncodedEphemeralPublicKey: String = try container.decode(String.self, forKey: .ephemeralPublicKey) let base64EncodedEphemeralPublicKey: String = try container.decode(String.self, forKey: .ephemeralPublicKey)
guard let ciphertext = Data(base64Encoded: base64EncodedCiphertext), let ephemeralPublicKey = Data(base64Encoded: base64EncodedEphemeralPublicKey) else { guard let ciphertext = Data(base64Encoded: base64EncodedCiphertext), let ephemeralPublicKey = Data(base64Encoded: base64EncodedEphemeralPublicKey) else {
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
self = OpenGroupAPIV2.AuthTokenResponse.Challenge( self = OpenGroupAPI.AuthTokenResponse.Challenge(
ciphertext: ciphertext, ciphertext: ciphertext,
ephemeralPublicKey: ephemeralPublicKey ephemeralPublicKey: ephemeralPublicKey
) )

View file

@ -5,7 +5,7 @@ import PromiseKit
import SessionUtilitiesKit import SessionUtilitiesKit
import SessionSnodeKit import SessionSnodeKit
extension OpenGroupAPIV2 { extension OpenGroupAPI {
// MARK: - BatchSubRequest // MARK: - BatchSubRequest
struct BatchSubRequest: Codable { struct BatchSubRequest: Codable {
@ -68,17 +68,17 @@ public extension Decodable {
} }
extension Promise where T == (OnionRequestResponseInfoType, Data?) { extension Promise where T == (OnionRequestResponseInfoType, Data?) {
func decoded(as types: OpenGroupAPIV2.BatchResponseTypes, on queue: DispatchQueue? = nil, error: Error) -> Promise<OpenGroupAPIV2.BatchResponse> { func decoded(as types: OpenGroupAPI.BatchResponseTypes, on queue: DispatchQueue? = nil, error: Error) -> Promise<OpenGroupAPI.BatchResponse> {
self.map(on: queue) { responseInfo, maybeData -> OpenGroupAPIV2.BatchResponse in self.map(on: queue) { responseInfo, maybeData -> OpenGroupAPI.BatchResponse in
// Need to split the data into an array of data so each item can be Decoded correctly // Need to split the data into an array of data so each item can be Decoded correctly
guard let data: Data = maybeData else { throw OpenGroupAPIV2.Error.parsingFailed } guard let data: Data = maybeData else { throw OpenGroupAPI.Error.parsingFailed }
guard let jsonObject: Any = try? JSONSerialization.jsonObject(with: data, options: [.fragmentsAllowed]) else { guard let jsonObject: Any = try? JSONSerialization.jsonObject(with: data, options: [.fragmentsAllowed]) else {
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
guard let anyArray: [Any] = jsonObject as? [Any] else { throw OpenGroupAPIV2.Error.parsingFailed } guard let anyArray: [Any] = jsonObject as? [Any] else { throw OpenGroupAPI.Error.parsingFailed }
let dataArray: [Data] = anyArray.compactMap { try? JSONSerialization.data(withJSONObject: $0) } let dataArray: [Data] = anyArray.compactMap { try? JSONSerialization.data(withJSONObject: $0) }
guard dataArray.count == types.count else { throw OpenGroupAPIV2.Error.parsingFailed } guard dataArray.count == types.count else { throw OpenGroupAPI.Error.parsingFailed }
do { do {
return try zip(dataArray, types) return try zip(dataArray, types)

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct Capabilities: Codable { public struct Capabilities: Codable {
public enum Capability: CaseIterable, Codable { public enum Capability: CaseIterable, Codable {
public static var allCases: [Capability] { public static var allCases: [Capability] {

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct DeletedMessagesResponse: Codable { struct DeletedMessagesResponse: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case deletions = "ids" case deletions = "ids"

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct Deletion: Codable { public struct Deletion: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case id case id

View file

@ -0,0 +1,19 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
extension OpenGroupAPI {
public struct DirectMessage: Codable {
enum CodingKeys: String, CodingKey {
case id
case sender
case expires = "expires_at"
case base64EncodedData = "data"
}
public let id: Int64
public let sender: String
public let expires: TimeInterval
public let base64EncodedData: String
}
}

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct FileResponse: Codable { public struct FileResponse: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case fileName = "filename" case fileName = "filename"

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct LegacyCompactPollBody: Codable { struct LegacyCompactPollBody: Codable {
struct Room: Codable { struct Room: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct LegacyCompactPollResponse: Codable { public struct LegacyCompactPollResponse: Codable {
public struct Result: Codable { public struct Result: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct LegacyGetInfoResponse: Codable { struct LegacyGetInfoResponse: Codable {
let room: LegacyRoomInfo let room: LegacyRoomInfo
} }

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct LegacyRoomInfo: Codable { public struct LegacyRoomInfo: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case id case id

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct LegacyRoomsResponse: Codable { struct LegacyRoomsResponse: Codable {
let rooms: [LegacyRoomInfo] let rooms: [LegacyRoomInfo]
} }

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct MemberCountResponse: Codable { struct MemberCountResponse: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case memberCount = "member_count" case memberCount = "member_count"

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct ModeratorsResponse: Codable { struct ModeratorsResponse: Codable {
let moderators: [String] let moderators: [String]
} }

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct Message: Codable { public struct Message: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case id case id
@ -34,7 +34,7 @@ extension OpenGroupAPIV2 {
// MARK: - Decoder // MARK: - Decoder
extension OpenGroupAPIV2.Message { extension OpenGroupAPI.Message {
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self) let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
@ -45,7 +45,7 @@ extension OpenGroupAPIV2.Message {
// If we have data and a signature (ie. the message isn't a deletion) then validate the signature // If we have data and a signature (ie. the message isn't a deletion) then validate the signature
if let base64EncodedData: String = maybeBase64EncodedData, let base64EncodedSignature: String = maybeBase64EncodedSignature { if let base64EncodedData: String = maybeBase64EncodedData, let base64EncodedSignature: String = maybeBase64EncodedSignature {
guard let sender: String = maybeSender, let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else { guard let sender: String = maybeSender, let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else {
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
let publicKey: Data = Data(hex: sender.removingIdPrefixIfNeeded()) let publicKey: Data = Data(hex: sender.removingIdPrefixIfNeeded())
@ -53,11 +53,11 @@ extension OpenGroupAPIV2.Message {
guard isValid else { guard isValid else {
SNLog("Ignoring message with invalid signature.") SNLog("Ignoring message with invalid signature.")
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
} }
self = OpenGroupAPIV2.Message( self = OpenGroupAPI.Message(
id: try container.decode(Int64.self, forKey: .id), id: try container.decode(Int64.self, forKey: .id),
sender: try? container.decode(String.self, forKey: .sender), sender: try? container.decode(String.self, forKey: .sender),
posted: try container.decode(TimeInterval.self, forKey: .posted), posted: try container.decode(TimeInterval.self, forKey: .posted),

View file

@ -49,7 +49,7 @@ extension OpenGroupMessageV2 {
// Validate the message signature // Validate the message signature
guard let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else { guard let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else {
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
let publicKey = Data(hex: sender.removingIdPrefixIfNeeded()) let publicKey = Data(hex: sender.removingIdPrefixIfNeeded())
@ -57,7 +57,7 @@ extension OpenGroupMessageV2 {
guard isValid else { guard isValid else {
SNLog("Ignoring message with invalid signature.") SNLog("Ignoring message with invalid signature.")
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
self = OpenGroupMessageV2( self = OpenGroupMessageV2(

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct PinnedMessage: Codable { public struct PinnedMessage: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case id case id

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct PublicKeyBody: Codable { struct PublicKeyBody: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case publicKey = "public_key" case publicKey = "public_key"

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct Room: Codable { public struct Room: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case token case token
@ -68,11 +68,11 @@ extension OpenGroupAPIV2 {
// MARK: - Decoding // MARK: - Decoding
extension OpenGroupAPIV2.Room { extension OpenGroupAPI.Room {
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self) let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
self = OpenGroupAPIV2.Room( self = OpenGroupAPI.Room(
token: try container.decode(String.self, forKey: .token), token: try container.decode(String.self, forKey: .token),
created: try container.decode(TimeInterval.self, forKey: .created), created: try container.decode(TimeInterval.self, forKey: .created),
name: try container.decode(String.self, forKey: .name), name: try container.decode(String.self, forKey: .name),
@ -83,7 +83,7 @@ extension OpenGroupAPIV2.Room {
messageSequence: try container.decode(Int64.self, forKey: .messageSequence), messageSequence: try container.decode(Int64.self, forKey: .messageSequence),
activeUsers: try container.decode(Int64.self, forKey: .activeUsers), activeUsers: try container.decode(Int64.self, forKey: .activeUsers),
activeUsersCutoff: try container.decode(Int64.self, forKey: .activeUsersCutoff), activeUsersCutoff: try container.decode(Int64.self, forKey: .activeUsersCutoff),
pinnedMessages: try? container.decode([OpenGroupAPIV2.PinnedMessage].self, forKey: .pinnedMessages), pinnedMessages: try? container.decode([OpenGroupAPI.PinnedMessage].self, forKey: .pinnedMessages),
admin: ((try? container.decode(Bool.self, forKey: .admin)) ?? false), admin: ((try? container.decode(Bool.self, forKey: .admin)) ?? false),
globalAdmin: ((try? container.decode(Bool.self, forKey: .globalAdmin)) ?? false), globalAdmin: ((try? container.decode(Bool.self, forKey: .globalAdmin)) ?? false),

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
/// This only contains ephemeral data /// This only contains ephemeral data
public struct RoomPollInfo: Codable { public struct RoomPollInfo: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {

View file

@ -0,0 +1,19 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
extension OpenGroupAPI {
public struct SendDirectMessageRequest: Codable {
let data: Data
let signature: Data
// MARK: - Encodable
public func encode(to encoder: Encoder) throws {
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
try container.encode(data.base64EncodedString(), forKey: .data)
try container.encode(signature.base64EncodedString(), forKey: .signature)
}
}
}

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct SendMessageRequest: Codable { public struct SendMessageRequest: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case data case data

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct UserBanRequest: Codable { struct UserBanRequest: Codable {
let rooms: [String]? let rooms: [String]?
let global: Bool? let global: Bool?

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct UserDeleteMessagesRequest: Codable { struct UserDeleteMessagesRequest: Codable {
let rooms: [String]? let rooms: [String]?
let global: Bool? let global: Bool?

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct UserDeleteMessagesResponse: Codable { public struct UserDeleteMessagesResponse: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case id case id

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct UserModeratorRequest: Codable { struct UserModeratorRequest: Codable {
/// List of room tokens to which the moderator status should be applied. The invoking user must be an admin of all of the given rooms. /// List of room tokens to which the moderator status should be applied. The invoking user must be an admin of all of the given rooms.
/// ///

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct UserPermissionsRequest: Codable { struct UserPermissionsRequest: Codable {
let rooms: [String] let rooms: [String]
let timeout: TimeInterval let timeout: TimeInterval

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct UserUnbanRequest: Codable { struct UserUnbanRequest: Codable {
let rooms: [String]? let rooms: [String]?
let global: Bool? let global: Bool?

View file

@ -1,10 +1,10 @@
import PromiseKit import PromiseKit
extension OpenGroupAPIV2 { extension OpenGroupAPI {
@objc(deleteMessageWithServerID:fromRoom:onServer:) @objc(deleteMessageWithServerID:fromRoom:onServer:)
public static func objc_deleteMessage(with serverID: Int64, from room: String, on server: String) -> AnyPromise { public static func objc_deleteMessage(with serverID: Int64, from room: String, on server: String) -> AnyPromise {
// TODO: Upgrade this to use the non-legacy version // TODO: Upgrade this to use the non-legacy version.
return AnyPromise.from(legacyDeleteMessage(with: serverID, from: room, on: server)) return AnyPromise.from(legacyDeleteMessage(with: serverID, from: room, on: server))
} }

View file

@ -3,8 +3,8 @@ import SessionSnodeKit
import Sodium import Sodium
import Curve25519Kit import Curve25519Kit
@objc(SNOpenGroupAPIV2) @objc(SNOpenGroupAPI)
public final class OpenGroupAPIV2: NSObject { public final class OpenGroupAPI: NSObject {
// MARK: - Settings // MARK: - Settings
@ -16,7 +16,7 @@ public final class OpenGroupAPIV2: NSObject {
private static var authTokenPromises: Atomic<[String: Promise<String>]> = Atomic([:]) private static var authTokenPromises: Atomic<[String: Promise<String>]> = Atomic([:])
private static var hasPerformedInitialPoll: [String: Bool] = [:] private static var hasPerformedInitialPoll: [String: Bool] = [:]
private static var hasUpdatedLastOpenDate = false private static var hasUpdatedLastOpenDate = false
public static let workQueue = DispatchQueue(label: "OpenGroupAPIV2.workQueue", qos: .userInitiated) // It's important that this is a serial queue public static let workQueue = DispatchQueue(label: "OpenGroupAPI.workQueue", qos: .userInitiated) // It's important that this is a serial queue
public static var moderators: [String: [String: Set<String>]] = [:] // Server URL to room ID to set of moderator IDs public static var moderators: [String: [String: Set<String>]] = [:] // Server URL to room ID to set of moderator IDs
public static var defaultRoomsPromise: Promise<[Room]>? public static var defaultRoomsPromise: Promise<[Room]>?
public static var groupImagePromises: [String: Promise<Data>] = [:] public static var groupImagePromises: [String: Promise<Data>] = [:]
@ -30,13 +30,7 @@ public final class OpenGroupAPIV2: NSObject {
// MARK: - Batching & Polling // MARK: - Batching & Polling
/// This is a convenience method which calls `/batch` with a pre-defined set of requests used to update an Open Group /// This is a convenience method which calls `/batch` with a pre-defined set of requests used to update an Open Group
public static func poll( public static func poll(_ server: String, using dependencies: Dependencies = Dependencies()) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable)]> {
_ server: String,
through api: OnionRequestAPIType.Type = OnionRequestAPI.self,
using storage: SessionMessagingKitStorageProtocol = SNMessagingKitConfiguration.shared.storage,
nonceGenerator: NonceGenerator16ByteType = NonceGenerator16Byte(),
date: Date = Date()
) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable)]> {
// TODO: Remove comments // TODO: Remove comments
// Capabilities // Capabilities
// Fetch each room // Fetch each room
@ -64,10 +58,10 @@ public final class OpenGroupAPIV2: NSObject {
) )
] ]
.appending( .appending(
storage.getAllV2OpenGroups().values dependencies.storage.getAllV2OpenGroups().values
.filter { $0.server == server.lowercased() } // Note: The `OpenGroupV2` converts the server value to lowercase during init .filter { $0.server == server.lowercased() } // Note: The `OpenGroupV2` converts the server value to lowercase during init
.flatMap { openGroup -> [BatchRequestInfo] in .flatMap { openGroup -> [BatchRequestInfo] in
let lastSeqNo: Int64? = storage.getLastMessageServerID(for: openGroup.room, on: server) let lastSeqNo: Int64? = dependencies.storage.getLastMessageServerID(for: openGroup.room, on: server)
let targetSeqNo: Int64 = (lastSeqNo ?? 0) let targetSeqNo: Int64 = (lastSeqNo ?? 0)
return [ return [
@ -93,8 +87,8 @@ public final class OpenGroupAPIV2: NSObject {
} }
) )
// TODO: Handle response (maybe in the poller or the OpenGroupManagerV2?) // TODO: Handle response (maybe in the poller or the OpenGroupManagerV2?).
return batch(server, requests: requestResponseType, through: api, using: storage, nonceGenerator: nonceGenerator, date: date) return batch(server, requests: requestResponseType, using: dependencies)
} }
/// This is used, for example, to poll multiple rooms on the same server for updates in a single query rather than needing to make multiple requests for each room. /// This is used, for example, to poll multiple rooms on the same server for updates in a single query rather than needing to make multiple requests for each room.
@ -102,14 +96,7 @@ public final class OpenGroupAPIV2: NSObject {
/// No guarantee is made as to the order in which sub-requests are processed; use the `/sequence` instead if you need that. /// No guarantee is made as to the order in which sub-requests are processed; use the `/sequence` instead if you need that.
/// ///
/// For contained subrequests that specify a body (i.e. POST or PUT requests) exactly one of `json`, `b64`, or `bytes` must be provided with the request body. /// For contained subrequests that specify a body (i.e. POST or PUT requests) exactly one of `json`, `b64`, or `bytes` must be provided with the request body.
private static func batch( private static func batch(_ server: String, requests: [BatchRequestInfo], using dependencies: Dependencies = Dependencies()) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable)]> {
_ server: String,
requests: [BatchRequestInfo],
through api: OnionRequestAPIType.Type = OnionRequestAPI.self,
using storage: SessionMessagingKitStorageProtocol = SNMessagingKitConfiguration.shared.storage,
nonceGenerator: NonceGenerator16ByteType = NonceGenerator16Byte(),
date: Date = Date()
) -> Promise<[Endpoint: (OnionRequestResponseInfoType, Codable)]> {
let requestBody: BatchRequest = requests.map { BatchSubRequest(request: $0.request) } let requestBody: BatchRequest = requests.map { BatchSubRequest(request: $0.request) }
let responseTypes = requests.map { $0.responseType } let responseTypes = requests.map { $0.responseType }
@ -124,8 +111,8 @@ public final class OpenGroupAPIV2: NSObject {
body: body body: body
) )
return send(request, through: api, using: storage, nonceGenerator: nonceGenerator, date: date) return send(request, using: dependencies)
.decoded(as: responseTypes, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: responseTypes, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
.map { result in .map { result in
result.enumerated() result.enumerated()
.reduce(into: [:]) { prev, next in .reduce(into: [:]) { prev, next in
@ -134,11 +121,10 @@ public final class OpenGroupAPIV2: NSObject {
} }
} }
// TODO: `/sequence` request // TODO: `/sequence` request.
public static func compactPoll(_ server: String, api: OnionRequestAPIType.Type = OnionRequestAPI.self) -> Promise<LegacyCompactPollResponse> { public static func compactPoll(_ server: String, using dependencies: Dependencies = Dependencies()) -> Promise<LegacyCompactPollResponse> {
let storage: SessionMessagingKitStorageProtocol = SNMessagingKitConfiguration.shared.storage let rooms: [String] = dependencies.storage.getAllV2OpenGroups().values
let rooms: [String] = storage.getAllV2OpenGroups().values
.filter { $0.server == server } .filter { $0.server == server }
.map { $0.room } .map { $0.room }
let useMessageLimit = (hasPerformedInitialPoll[server] != true && timeSinceLastOpen > OpenGroupPollerV2.maxInactivityPeriod) let useMessageLimit = (hasPerformedInitialPoll[server] != true && timeSinceLastOpen > OpenGroupPollerV2.maxInactivityPeriod)
@ -146,7 +132,7 @@ public final class OpenGroupAPIV2: NSObject {
hasPerformedInitialPoll[server] = true hasPerformedInitialPoll[server] = true
if !hasUpdatedLastOpenDate { if !hasUpdatedLastOpenDate {
UserDefaults.standard[.lastOpen] = Date() UserDefaults.standard[.lastOpen] = dependencies.date
hasUpdatedLastOpenDate = true hasUpdatedLastOpenDate = true
} }
@ -156,10 +142,10 @@ public final class OpenGroupAPIV2: NSObject {
LegacyCompactPollBody.Room( LegacyCompactPollBody.Room(
id: roomId, id: roomId,
fromMessageServerId: (useMessageLimit ? nil : fromMessageServerId: (useMessageLimit ? nil :
storage.getLastMessageServerID(for: roomId, on: server) dependencies.storage.getLastMessageServerID(for: roomId, on: server)
), ),
fromDeletionServerId: (useMessageLimit ? nil : fromDeletionServerId: (useMessageLimit ? nil :
storage.getLastDeletionServerID(for: roomId, on: server) dependencies.storage.getLastDeletionServerID(for: roomId, on: server)
), ),
legacyAuthToken: nil legacyAuthToken: nil
) )
@ -177,8 +163,8 @@ public final class OpenGroupAPIV2: NSObject {
body: body body: body
) )
return send(request, through: api) return send(request, using: dependencies)
.then(on: OpenGroupAPIV2.workQueue) { _, maybeData -> Promise<LegacyCompactPollResponse> in .then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise<LegacyCompactPollResponse> in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyCompactPollResponse = try data.decoded(as: LegacyCompactPollResponse.self, customError: Error.parsingFailed) let response: LegacyCompactPollResponse = try data.decoded(as: LegacyCompactPollResponse.self, customError: Error.parsingFailed)
@ -187,11 +173,11 @@ public final class OpenGroupAPIV2: NSObject {
fulfilled: response.results fulfilled: response.results
.map { (result: LegacyCompactPollResponse.Result) in .map { (result: LegacyCompactPollResponse.Result) in
legacyProcess(messages: result.messages, for: result.room, on: server) legacyProcess(messages: result.messages, for: result.room, on: server)
.then(on: OpenGroupAPIV2.workQueue) { _ in .then(on: OpenGroupAPI.workQueue) { _ in
process(deletions: result.deletions, for: result.room, on: server) process(deletions: result.deletions, for: result.room, on: server)
} }
} }
).then(on: OpenGroupAPIV2.workQueue) { _ in Promise.value(response) } ).then(on: OpenGroupAPI.workQueue) { _ in Promise.value(response) }
} }
} }
@ -204,9 +190,9 @@ public final class OpenGroupAPIV2: NSObject {
queryParameters: [:] // TODO: Add any requirements '.required'. queryParameters: [:] // TODO: Add any requirements '.required'.
) )
// TODO: Handle a `412` response (ie. a required capability isn't supported). // TODO: Handle a `412` response (ie. a required capability isn't supported)
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: Capabilities.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: Capabilities.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
// MARK: - Room // MARK: - Room
@ -218,7 +204,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: [Room].self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: [Room].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
public static func room(for roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, Room)> { public static func room(for roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, Room)> {
@ -228,7 +214,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: Room.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: Room.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
public static func roomPollInfo(lastUpdated: Int64, for roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, RoomPollInfo)> { public static func roomPollInfo(lastUpdated: Int64, for roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, RoomPollInfo)> {
@ -238,7 +224,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: RoomPollInfo.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: RoomPollInfo.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
// MARK: - Messages // MARK: - Messages
@ -262,7 +248,7 @@ public final class OpenGroupAPIV2: NSObject {
signature: signedRequest.signature, signature: signedRequest.signature,
whisperTo: whisperTo, whisperTo: whisperTo,
whisperMods: whisperMods, whisperMods: whisperMods,
fileIds: nil // TODO: Add support for 'fileIds' fileIds: nil // TODO: Add support for 'fileIds'.
) )
guard let body: Data = try? JSONEncoder().encode(requestBody) else { guard let body: Data = try? JSONEncoder().encode(requestBody) else {
@ -277,60 +263,61 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: Message.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: Message.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
public static func recentMessages(in roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [Message])> { public static func recentMessages(in roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [Message])> {
// TODO: Recent vs. Since?.
let request: Request = Request( let request: Request = Request(
server: server, server: server,
endpoint: .roomMessagesRecent(roomToken) endpoint: .roomMessagesRecent(roomToken)
// TODO: Limit? // TODO: Limit?.
// queryParameters: [ // queryParameters: [
// .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) } // .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) }
// ].compactMapValues { $0 } // ].compactMapValues { $0 }
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: [Message].self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: [Message].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
.then(on: OpenGroupAPIV2.workQueue) { responseInfo, messages -> Promise<(OnionRequestResponseInfoType, [Message])> in .then(on: OpenGroupAPI.workQueue) { responseInfo, messages -> Promise<(OnionRequestResponseInfoType, [Message])> in
process(messages: messages, for: roomToken, on: server, using: dependencies) process(messages: messages, for: roomToken, on: server, using: dependencies)
.map { processedMessages in (responseInfo, processedMessages) } .map { processedMessages in (responseInfo, processedMessages) }
} }
} }
public static func messagesBefore(messageId: Int64, in roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [Message])> { public static func messagesBefore(messageId: Int64, in roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [Message])> {
// TODO: Recent vs. Since? // TODO: Recent vs. Since?.
let request: Request = Request( let request: Request = Request(
server: server, server: server,
endpoint: .roomMessagesBefore(roomToken, id: messageId) endpoint: .roomMessagesBefore(roomToken, id: messageId)
// TODO: Limit? // TODO: Limit?.
// queryParameters: [ // queryParameters: [
// .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) } // .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) }
// ].compactMapValues { $0 } // ].compactMapValues { $0 }
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: [Message].self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: [Message].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
.then(on: OpenGroupAPIV2.workQueue) { responseInfo, messages -> Promise<(OnionRequestResponseInfoType, [Message])> in .then(on: OpenGroupAPI.workQueue) { responseInfo, messages -> Promise<(OnionRequestResponseInfoType, [Message])> in
process(messages: messages, for: roomToken, on: server, using: dependencies) process(messages: messages, for: roomToken, on: server, using: dependencies)
.map { processedMessages in (responseInfo, processedMessages) } .map { processedMessages in (responseInfo, processedMessages) }
} }
} }
public static func messagesSince(seqNo: Int64, in roomToken: String, on server: String) -> Promise<(OnionRequestResponseInfoType, [Message])> { public static func messagesSince(seqNo: Int64, in roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [Message])> {
// TODO: Recent vs. Since? // TODO: Recent vs. Since?.
let request: Request = Request( let request: Request = Request(
server: server, server: server,
endpoint: .roomMessagesSince(roomToken, seqNo: seqNo) endpoint: .roomMessagesSince(roomToken, seqNo: seqNo)
// TODO: Limit? // TODO: Limit?.
// queryParameters: [ // queryParameters: [
// .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) } // .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) }
// ].compactMapValues { $0 } // ].compactMapValues { $0 }
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: [Message].self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: [Message].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
.then(on: OpenGroupAPIV2.workQueue) { responseInfo, messages -> Promise<(OnionRequestResponseInfoType, [Message])> in .then(on: OpenGroupAPI.workQueue) { responseInfo, messages -> Promise<(OnionRequestResponseInfoType, [Message])> in
process(messages: messages, for: roomToken, on: server, using: dependencies) process(messages: messages, for: roomToken, on: server, using: dependencies)
.map { processedMessages in (responseInfo, processedMessages) } .map { processedMessages in (responseInfo, processedMessages) }
} }
@ -373,7 +360,7 @@ public final class OpenGroupAPIV2: NSObject {
// MARK: - Files // MARK: - Files
// TODO: Shift this logic to the `OpenGroupManager` (makes more sense since it's not API logic) // TODO: Shift this logic to the `OpenGroupManager` (makes more sense since it's not API logic).
public static func roomImage(_ fileId: Int64, for roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<Data> { public static func roomImage(_ fileId: Int64, for roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<Data> {
// Normally the image for a given group is stored with the group thread, so it's only // Normally the image for a given group is stored with the group thread, so it's only
// fetched once. However, on the join open group screen we show images for groups the // fetched once. However, on the join open group screen we show images for groups the
@ -399,7 +386,7 @@ public final class OpenGroupAPIV2: NSObject {
let promise: Promise<Data> = downloadFile(fileId, from: roomToken, on: server, using: dependencies) let promise: Promise<Data> = downloadFile(fileId, from: roomToken, on: server, using: dependencies)
.map { _, data in data } .map { _, data in data }
_ = promise.done(on: OpenGroupAPIV2.workQueue) { imageData in _ = promise.done(on: OpenGroupAPI.workQueue) { imageData in
if server == defaultServer { if server == defaultServer {
dependencies.storage.write { transaction in dependencies.storage.write { transaction in
dependencies.storage.setOpenGroupImage(to: imageData, for: roomToken, on: server, using: transaction) dependencies.storage.setOpenGroupImage(to: imageData, for: roomToken, on: server, using: transaction)
@ -422,7 +409,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: FileUploadResponse.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: FileUploadResponse.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
/// Warning: This approach is less efficient as it expects the data to be base64Encoded (with is 33% larger than binary), please use the binary approach /// Warning: This approach is less efficient as it expects the data to be base64Encoded (with is 33% larger than binary), please use the binary approach
@ -437,7 +424,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: FileUploadResponse.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: FileUploadResponse.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
public static func downloadFile(_ fileId: Int64, from roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, Data)> { public static func downloadFile(_ fileId: Int64, from roomToken: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, Data)> {
@ -459,9 +446,57 @@ public final class OpenGroupAPIV2: NSObject {
server: server, server: server,
endpoint: .roomFileIndividualJson(roomToken, fileId) endpoint: .roomFileIndividualJson(roomToken, fileId)
) )
// TODO: This endpoint is getting rewritten to return just data (properties would come through as headers) // TODO: This endpoint is getting rewritten to return just data (properties would come through as headers).
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: FileDownloadResponse.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: FileDownloadResponse.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
}
// MARK: - Inbox (Message Requests)
public static func messageRequests(on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [DirectMessage])> {
let request: Request = Request(
server: server,
endpoint: .inbox
)
return send(request, using: dependencies)
.decoded(as: [DirectMessage].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
}
public static func messageRequestsSince(id: Int64, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [DirectMessage])> {
let request: Request = Request(
server: server,
endpoint: .inboxSince(id: id)
)
return send(request, using: dependencies)
.decoded(as: [DirectMessage].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
}
public static func sendMessageRequest(_ plaintext: Data, to sessionId: String, on server: String, with serverPublicKey: String, using dependencies: Dependencies = Dependencies()) -> Promise<(OnionRequestResponseInfoType, [DirectMessage])> {
// TODO: Change this to use '.blinded' once it's working
guard let signedRequest: (data: Data, signature: Data) = SendMessageRequest.sign(message: plaintext, for: .standard, with: serverPublicKey) else {
return Promise(error: Error.signingFailed)
}
let requestBody: SendDirectMessageRequest = SendDirectMessageRequest(
data: signedRequest.data,
signature: signedRequest.signature
)
guard let body: Data = try? JSONEncoder().encode(requestBody) else {
return Promise(error: Error.parsingFailed)
}
let request: Request = Request(
method: .post,
server: server,
endpoint: .inboxFor(sessionId: sessionId),
body: body
)
return send(request, using: dependencies)
.decoded(as: [DirectMessage].self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
// MARK: - Users // MARK: - Users
@ -571,11 +606,11 @@ public final class OpenGroupAPIV2: NSObject {
) )
return send(request, using: dependencies) return send(request, using: dependencies)
.decoded(as: UserDeleteMessagesResponse.self, on: OpenGroupAPIV2.workQueue, error: Error.parsingFailed) .decoded(as: UserDeleteMessagesResponse.self, on: OpenGroupAPI.workQueue, error: Error.parsingFailed)
} }
// MARK: - Processing // MARK: - Processing
// TODO: Move these methods to the OpenGroupManager? (seems odd for them to be in the API) // TODO: Move these methods to the OpenGroupManager? (seems odd for them to be in the API).
private static func process(messages: [Message]?, for room: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<[Message]> { private static func process(messages: [Message]?, for room: String, on server: String, using dependencies: Dependencies = Dependencies()) -> Promise<[Message]> {
guard let messages: [Message] = messages, !messages.isEmpty else { return Promise.value([]) } guard let messages: [Message] = messages, !messages.isEmpty else { return Promise.value([]) }
@ -631,7 +666,7 @@ public final class OpenGroupAPIV2: NSObject {
// MARK: - General // MARK: - General
// TODO: Shift this to the OpenGroupManagerV2? (seems more at place there than in the API) // TODO: Shift this to the OpenGroupManagerV2? (seems more at place there than in the API).
public static func getDefaultRoomsIfNeeded(using dependencies: Dependencies = Dependencies()) { public static func getDefaultRoomsIfNeeded(using dependencies: Dependencies = Dependencies()) {
Storage.shared.write( Storage.shared.write(
with: { transaction in with: { transaction in
@ -639,10 +674,10 @@ public final class OpenGroupAPIV2: NSObject {
}, },
completion: { completion: {
let promise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) { let promise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
OpenGroupAPIV2.rooms(for: defaultServer, using: dependencies) OpenGroupAPI.rooms(for: defaultServer, using: dependencies)
.map { _, data in data } .map { _, data in data }
} }
_ = promise.done(on: OpenGroupAPIV2.workQueue) { items in _ = promise.done(on: OpenGroupAPI.workQueue) { items in
items items
.compactMap { room -> (Int64, String)? in .compactMap { room -> (Int64, String)? in
guard let imageId: Int64 = room.imageId else { return nil} guard let imageId: Int64 = room.imageId else { return nil}
@ -654,8 +689,8 @@ public final class OpenGroupAPIV2: NSObject {
.retainUntilComplete() .retainUntilComplete()
} }
} }
promise.catch(on: OpenGroupAPIV2.workQueue) { _ in promise.catch(on: OpenGroupAPI.workQueue) { _ in
OpenGroupAPIV2.defaultRoomsPromise = nil OpenGroupAPI.defaultRoomsPromise = nil
} }
defaultRoomsPromise = promise defaultRoomsPromise = promise
} }
@ -681,7 +716,7 @@ public final class OpenGroupAPIV2: NSObject {
// guard let blindedKeyPair: ECKeyPair = try? userKeyPair.convert(to: .blinded, with: publicKey) else { // guard let blindedKeyPair: ECKeyPair = try? userKeyPair.convert(to: .blinded, with: publicKey) else {
// return nil // return nil
// } // }
// TODO: Change this back once you figure out why it's busted // TODO: Change this back once you figure out why it's busted.
let blindedKeyPair: ECKeyPair = userKeyPair let blindedKeyPair: ECKeyPair = userKeyPair
/// Generate the sharedSecret by "aB || A || B" where /// Generate the sharedSecret by "aB || A || B" where
@ -703,8 +738,10 @@ public final class OpenGroupAPIV2: NSObject {
let secretHashMessage: Bytes = method.bytes let secretHashMessage: Bytes = method.bytes
.appending(path.bytes) .appending(path.bytes)
.appending("\(timestamp)".bytes) .appending("\(timestamp)".bytes)
.appending(request.httpBody?.bytes ?? []) // TODO: Might need to do the 'httpBodyStream' as well??? .appending(request.httpBody?.bytes ?? []) // TODO: Might need to do the 'httpBodyStream' as well???.
print("RAWR 1 \(blindedKeyPair.hexEncodedPublicKey)")
print("RAWR 2 \(maybeSharedSecret?.hexadecimalString)")
print("RAWR '\(String(describing: String(data: Data(secretHashMessage), encoding: .utf8)))'")
guard let sharedSecret: Data = maybeSharedSecret else { return nil } guard let sharedSecret: Data = maybeSharedSecret else { return nil }
guard let intermediateHash: Bytes = dependencies.genericHash.hashSaltPersonal(message: sharedSecret.bytes, outputLength: 42, key: nil, salt: nonce.bytes, personal: Personalization.sharedKeys.bytes) else { guard let intermediateHash: Bytes = dependencies.genericHash.hashSaltPersonal(message: sharedSecret.bytes, outputLength: 42, key: nil, salt: nonce.bytes, personal: Personalization.sharedKeys.bytes) else {
return nil return nil
@ -712,7 +749,8 @@ public final class OpenGroupAPIV2: NSObject {
guard let secretHash: Bytes = dependencies.genericHash.hashSaltPersonal(message: secretHashMessage, outputLength: 42, key: intermediateHash, salt: nonce.bytes, personal: Personalization.authHeader.bytes) else { guard let secretHash: Bytes = dependencies.genericHash.hashSaltPersonal(message: secretHashMessage, outputLength: 42, key: intermediateHash, salt: nonce.bytes, personal: Personalization.authHeader.bytes) else {
return nil return nil
} }
print("RAWR3 '\(intermediateHash.toHexString())'") // This is the one we can compare
print("RAWR4 '\(secretHash.toHexString())'")
updatedRequest.allHTTPHeaderFields = (request.allHTTPHeaderFields ?? [:]) updatedRequest.allHTTPHeaderFields = (request.allHTTPHeaderFields ?? [:])
.updated(with: [ .updated(with: [
Header.sogsPubKey.rawValue: blindedKeyPair.hexEncodedPublicKey, Header.sogsPubKey.rawValue: blindedKeyPair.hexEncodedPublicKey,
@ -747,7 +785,7 @@ public final class OpenGroupAPIV2: NSObject {
return Promise(error: Error.signingFailed) return Promise(error: Error.signingFailed)
} }
// TODO: 'removeAuthToken' as a migration??? (would previously do this when getting a `401`). // TODO: 'removeAuthToken' as a migration??? (would previously do this when getting a `401`)
return dependencies.api.sendOnionRequest(signedRequest, to: request.server, with: publicKey) return dependencies.api.sendOnionRequest(signedRequest, to: request.server, with: publicKey)
} }
@ -779,8 +817,8 @@ public final class OpenGroupAPIV2: NSObject {
} }
let promise: Promise<String> = legacyRequestNewAuthToken(for: room, on: server) let promise: Promise<String> = legacyRequestNewAuthToken(for: room, on: server)
.then(on: OpenGroupAPIV2.workQueue) { legacyClaimAuthToken($0, for: room, on: server) } .then(on: OpenGroupAPI.workQueue) { legacyClaimAuthToken($0, for: room, on: server) }
.then(on: OpenGroupAPIV2.workQueue) { authToken -> Promise<String> in .then(on: OpenGroupAPI.workQueue) { authToken -> Promise<String> in
let (promise, seal) = Promise<String>.pending() let (promise, seal) = Promise<String>.pending()
storage.write(with: { transaction in storage.write(with: { transaction in
storage.setAuthToken(for: room, on: server, to: authToken, using: transaction) storage.setAuthToken(for: room, on: server, to: authToken, using: transaction)
@ -791,10 +829,10 @@ public final class OpenGroupAPIV2: NSObject {
} }
promise promise
.done(on: OpenGroupAPIV2.workQueue) { _ in .done(on: OpenGroupAPI.workQueue) { _ in
authTokenPromises.wrappedValue["\(server).\(room)"] = nil authTokenPromises.wrappedValue["\(server).\(room)"] = nil
} }
.catch(on: OpenGroupAPIV2.workQueue) { _ in .catch(on: OpenGroupAPI.workQueue) { _ in
authTokenPromises.wrappedValue["\(server).\(room)"] = nil authTokenPromises.wrappedValue["\(server).\(room)"] = nil
} }
@ -819,7 +857,7 @@ public final class OpenGroupAPIV2: NSObject {
isAuthRequired: false isAuthRequired: false
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _, maybeData in return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response = try data.decoded(as: AuthTokenResponse.self, customError: Error.parsingFailed) let response = try data.decoded(as: AuthTokenResponse.self, customError: Error.parsingFailed)
let symmetricKey = try AESGCM.generateSymmetricKey(x25519PublicKey: response.challenge.ephemeralPublicKey, x25519PrivateKey: userKeyPair.privateKey) let symmetricKey = try AESGCM.generateSymmetricKey(x25519PublicKey: response.challenge.ephemeralPublicKey, x25519PrivateKey: userKeyPair.privateKey)
@ -853,7 +891,7 @@ public final class OpenGroupAPIV2: NSObject {
isAuthRequired: false isAuthRequired: false
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _ in authToken } return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in authToken }
} }
/// Should be called when leaving a group. /// Should be called when leaving a group.
@ -866,7 +904,7 @@ public final class OpenGroupAPIV2: NSObject {
endpoint: .legacyAuthToken(legacyAuth: true) endpoint: .legacyAuthToken(legacyAuth: true)
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _ in return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in
let storage = SNMessagingKitConfiguration.shared.storage let storage = SNMessagingKitConfiguration.shared.storage
storage.write { transaction in storage.write { transaction in
@ -914,7 +952,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return when(fulfilled: [Promise<String>](getAuthTokenPromises.values)) return when(fulfilled: [Promise<String>](getAuthTokenPromises.values))
.then(on: OpenGroupAPIV2.workQueue) { _ -> Promise<LegacyCompactPollResponse> in .then(on: OpenGroupAPI.workQueue) { _ -> Promise<LegacyCompactPollResponse> in
let requestBodyWithAuthTokens: LegacyCompactPollBody = LegacyCompactPollBody( let requestBodyWithAuthTokens: LegacyCompactPollBody = LegacyCompactPollBody(
requests: requestBody.requests.compactMap { oldRoom -> LegacyCompactPollBody.Room? in requests: requestBody.requests.compactMap { oldRoom -> LegacyCompactPollBody.Room? in
guard let authToken: String = getAuthTokenPromises[oldRoom.id]?.value else { return nil } guard let authToken: String = getAuthTokenPromises[oldRoom.id]?.value else { return nil }
@ -941,7 +979,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return legacySend(request) return legacySend(request)
.then(on: OpenGroupAPIV2.workQueue) { _, maybeData -> Promise<LegacyCompactPollResponse> in .then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise<LegacyCompactPollResponse> in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyCompactPollResponse = try data.decoded(as: LegacyCompactPollResponse.self, customError: Error.parsingFailed) let response: LegacyCompactPollResponse = try data.decoded(as: LegacyCompactPollResponse.self, customError: Error.parsingFailed)
@ -962,11 +1000,11 @@ public final class OpenGroupAPIV2: NSObject {
} }
return legacyProcess(messages: result.messages, for: result.room, on: server) return legacyProcess(messages: result.messages, for: result.room, on: server)
.then(on: OpenGroupAPIV2.workQueue) { _ -> Promise<[Deletion]> in .then(on: OpenGroupAPI.workQueue) { _ -> Promise<[Deletion]> in
legacyProcess(deletions: result.deletions, for: result.room, on: server) legacyProcess(deletions: result.deletions, for: result.room, on: server)
} }
} }
).then(on: OpenGroupAPIV2.workQueue) { _ in Promise.value(response) } ).then(on: OpenGroupAPI.workQueue) { _ in Promise.value(response) }
} }
} }
} }
@ -979,13 +1017,13 @@ public final class OpenGroupAPIV2: NSObject {
}, },
completion: { completion: {
let promise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) { let promise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) {
OpenGroupAPIV2.legacyGetAllRooms(from: defaultServer) OpenGroupAPI.legacyGetAllRooms(from: defaultServer)
} }
_ = promise.done(on: OpenGroupAPIV2.workQueue) { items in _ = promise.done(on: OpenGroupAPI.workQueue) { items in
items.forEach { legacyGetGroupImage(for: $0.id, on: defaultServer).retainUntilComplete() } items.forEach { legacyGetGroupImage(for: $0.id, on: defaultServer).retainUntilComplete() }
} }
promise.catch(on: OpenGroupAPIV2.workQueue) { _ in promise.catch(on: OpenGroupAPI.workQueue) { _ in
OpenGroupAPIV2.defaultRoomsPromise = nil OpenGroupAPI.defaultRoomsPromise = nil
} }
legacyDefaultRoomsPromise = promise legacyDefaultRoomsPromise = promise
} }
@ -1001,7 +1039,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return legacySend(request) return legacySend(request)
.map(on: OpenGroupAPIV2.workQueue) { _, maybeData in .map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyRoomsResponse = try data.decoded(as: LegacyRoomsResponse.self, customError: Error.parsingFailed) let response: LegacyRoomsResponse = try data.decoded(as: LegacyRoomsResponse.self, customError: Error.parsingFailed)
@ -1019,7 +1057,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return legacySend(request) return legacySend(request)
.map(on: OpenGroupAPIV2.workQueue) { _, maybeData in .map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyGetInfoResponse = try data.decoded(as: LegacyGetInfoResponse.self, customError: Error.parsingFailed) let response: LegacyGetInfoResponse = try data.decoded(as: LegacyGetInfoResponse.self, customError: Error.parsingFailed)
@ -1058,7 +1096,7 @@ public final class OpenGroupAPIV2: NSObject {
isAuthRequired: false isAuthRequired: false
) )
let promise: Promise<Data> = legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _, maybeData in let promise: Promise<Data> = legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyFileDownloadResponse = try data.decoded(as: LegacyFileDownloadResponse.self, customError: Error.parsingFailed) let response: LegacyFileDownloadResponse = try data.decoded(as: LegacyFileDownloadResponse.self, customError: Error.parsingFailed)
@ -1085,7 +1123,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return legacySend(request) return legacySend(request)
.map(on: OpenGroupAPIV2.workQueue) { _, maybeData in .map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: MemberCountResponse = try data.decoded(as: MemberCountResponse.self, customError: Error.parsingFailed) let response: MemberCountResponse = try data.decoded(as: MemberCountResponse.self, customError: Error.parsingFailed)
@ -1110,7 +1148,7 @@ public final class OpenGroupAPIV2: NSObject {
let request = Request(method: .post, server: server, room: room, endpoint: .legacyFiles, body: body) let request = Request(method: .post, server: server, room: room, endpoint: .legacyFiles, body: body)
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _, maybeData in return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyFileUploadResponse = try data.decoded(as: LegacyFileUploadResponse.self, customError: Error.parsingFailed) let response: LegacyFileUploadResponse = try data.decoded(as: LegacyFileUploadResponse.self, customError: Error.parsingFailed)
@ -1122,7 +1160,7 @@ public final class OpenGroupAPIV2: NSObject {
public static func legacyDownload(_ file: UInt64, from room: String, on server: String) -> Promise<Data> { public static func legacyDownload(_ file: UInt64, from room: String, on server: String) -> Promise<Data> {
let request = Request(server: server, room: room, endpoint: .legacyFile(file)) let request = Request(server: server, room: room, endpoint: .legacyFile(file))
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _, maybeData in return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: LegacyFileDownloadResponse = try data.decoded(as: LegacyFileDownloadResponse.self, customError: Error.parsingFailed) let response: LegacyFileDownloadResponse = try data.decoded(as: LegacyFileDownloadResponse.self, customError: Error.parsingFailed)
@ -1140,7 +1178,7 @@ public final class OpenGroupAPIV2: NSObject {
} }
let request = Request(method: .post, server: server, room: room, endpoint: .legacyMessages, body: body) let request = Request(method: .post, server: server, room: room, endpoint: .legacyMessages, body: body)
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _, maybeData in return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let message: OpenGroupMessageV2 = try data.decoded(as: OpenGroupMessageV2.self, customError: Error.parsingFailed) let message: OpenGroupMessageV2 = try data.decoded(as: OpenGroupMessageV2.self, customError: Error.parsingFailed)
Storage.shared.write { transaction in Storage.shared.write { transaction in
@ -1162,7 +1200,7 @@ public final class OpenGroupAPIV2: NSObject {
].compactMapValues { $0 } ].compactMapValues { $0 }
) )
return legacySend(request).then(on: OpenGroupAPIV2.workQueue) { _, maybeData -> Promise<[OpenGroupMessageV2]> in return legacySend(request).then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise<[OpenGroupMessageV2]> in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let messages: [OpenGroupMessageV2] = try data.decoded(as: [OpenGroupMessageV2].self, customError: Error.parsingFailed) let messages: [OpenGroupMessageV2] = try data.decoded(as: [OpenGroupMessageV2].self, customError: Error.parsingFailed)
@ -1172,7 +1210,7 @@ public final class OpenGroupAPIV2: NSObject {
// MARK: - Legacy Message Deletion // MARK: - Legacy Message Deletion
// TODO: No delete method???? // TODO: No delete method????.
@available(*, deprecated, message: "Use v4 endpoint instead") @available(*, deprecated, message: "Use v4 endpoint instead")
public static func legacyDeleteMessage(with serverID: Int64, from room: String, on server: String) -> Promise<Void> { public static func legacyDeleteMessage(with serverID: Int64, from room: String, on server: String) -> Promise<Void> {
let request: Request = Request( let request: Request = Request(
@ -1182,7 +1220,7 @@ public final class OpenGroupAPIV2: NSObject {
endpoint: .legacyMessagesForServer(serverID) endpoint: .legacyMessagesForServer(serverID)
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _ in } return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in }
} }
@available(*, deprecated, message: "Use v4 endpoint instead") @available(*, deprecated, message: "Use v4 endpoint instead")
@ -1198,7 +1236,7 @@ public final class OpenGroupAPIV2: NSObject {
].compactMapValues { $0 } ].compactMapValues { $0 }
) )
return legacySend(request).then(on: OpenGroupAPIV2.workQueue) { _, maybeData -> Promise<[Deletion]> in return legacySend(request).then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise<[Deletion]> in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: DeletedMessagesResponse = try data.decoded(as: DeletedMessagesResponse.self, customError: Error.parsingFailed) let response: DeletedMessagesResponse = try data.decoded(as: DeletedMessagesResponse.self, customError: Error.parsingFailed)
@ -1217,7 +1255,7 @@ public final class OpenGroupAPIV2: NSObject {
) )
return legacySend(request) return legacySend(request)
.map(on: OpenGroupAPIV2.workQueue) { _, maybeData in .map(on: OpenGroupAPI.workQueue) { _, maybeData in
guard let data: Data = maybeData else { throw Error.parsingFailed } guard let data: Data = maybeData else { throw Error.parsingFailed }
let response: ModeratorsResponse = try data.decoded(as: ModeratorsResponse.self, customError: Error.parsingFailed) let response: ModeratorsResponse = try data.decoded(as: ModeratorsResponse.self, customError: Error.parsingFailed)
@ -1249,7 +1287,7 @@ public final class OpenGroupAPIV2: NSObject {
body: body body: body
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _ in } return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in }
} }
@available(*, deprecated, message: "Use v4 endpoint instead") @available(*, deprecated, message: "Use v4 endpoint instead")
@ -1268,7 +1306,7 @@ public final class OpenGroupAPIV2: NSObject {
body: body body: body
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _ in } return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in }
} }
@available(*, deprecated, message: "Use v4 endpoint instead") @available(*, deprecated, message: "Use v4 endpoint instead")
@ -1280,7 +1318,7 @@ public final class OpenGroupAPIV2: NSObject {
endpoint: .legacyBlockListIndividual(publicKey) endpoint: .legacyBlockListIndividual(publicKey)
) )
return legacySend(request).map(on: OpenGroupAPIV2.workQueue) { _ in } return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in }
} }
// MARK: - Processing // MARK: - Processing
@ -1364,11 +1402,11 @@ public final class OpenGroupAPIV2: NSObject {
} }
return legacyGetAuthToken(for: room, on: request.server) return legacyGetAuthToken(for: room, on: request.server)
.then(on: OpenGroupAPIV2.workQueue) { authToken -> Promise<(OnionRequestResponseInfoType, Data?)> in .then(on: OpenGroupAPI.workQueue) { authToken -> Promise<(OnionRequestResponseInfoType, Data?)> in
urlRequest.setValue(authToken, forHTTPHeaderField: Header.authorization.rawValue) urlRequest.setValue(authToken, forHTTPHeaderField: Header.authorization.rawValue)
let promise = api.sendOnionRequest(urlRequest, to: request.server, using: .v3, with: publicKey) let promise = api.sendOnionRequest(urlRequest, to: request.server, using: .v3, with: publicKey)
promise.catch(on: OpenGroupAPIV2.workQueue) { error in promise.catch(on: OpenGroupAPI.workQueue) { error in
// A 401 means that we didn't provide a (valid) auth token for a route // A 401 means that we didn't provide a (valid) auth token for a route
// that required one. We use this as an indication that the token we're // that required one. We use this as an indication that the token we're
// using has expired. Note that a 403 has a different meaning; it means // using has expired. Note that a 403 has a different meaning; it means

View file

@ -42,7 +42,7 @@ public final class OpenGroupManagerV2 : NSObject {
transaction.addCompletionQueue(DispatchQueue.global(qos: .userInitiated)) { transaction.addCompletionQueue(DispatchQueue.global(qos: .userInitiated)) {
// Get the group info // Get the group info
// TODO: Remove this legacy method // TODO: Remove this legacy method
// OpenGroupAPIV2.legacyGetRoomInfo(for: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { info in // OpenGroupAPI.legacyGetRoomInfo(for: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { info in
// // Create the open group model and the thread // // Create the open group model and the thread
// let openGroup = OpenGroupV2(server: server, room: room, name: info.name, publicKey: publicKey, imageID: info.imageID) // let openGroup = OpenGroupV2(server: server, room: room, name: info.name, publicKey: publicKey, imageID: info.imageID)
// let groupID = LKGroupUtilities.getEncodedOpenGroupIDAsData(openGroup.id) // let groupID = LKGroupUtilities.getEncodedOpenGroupIDAsData(openGroup.id)
@ -62,7 +62,7 @@ public final class OpenGroupManagerV2 : NSObject {
// OpenGroupManagerV2.shared.pollers[server] = poller // OpenGroupManagerV2.shared.pollers[server] = poller
// } // }
// // Fetch the group image // // Fetch the group image
// OpenGroupAPIV2.legacyGetGroupImage(for: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in // OpenGroupAPI.legacyGetGroupImage(for: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { data in
// storage.write { transaction in // storage.write { transaction in
// // Update the thread // // Update the thread
// let transaction = transaction as! YapDatabaseReadWriteTransaction // let transaction = transaction as! YapDatabaseReadWriteTransaction
@ -78,7 +78,7 @@ public final class OpenGroupManagerV2 : NSObject {
// seal.reject(error) // seal.reject(error)
// } // }
OpenGroupAPIV2.room(for: room, on: server) OpenGroupAPI.room(for: room, on: server)
.done(on: DispatchQueue.global(qos: .userInitiated)) { _, room in .done(on: DispatchQueue.global(qos: .userInitiated)) { _, room in
// Create the open group model and the thread // Create the open group model and the thread
let openGroup: OpenGroupV2 = OpenGroupV2( let openGroup: OpenGroupV2 = OpenGroupV2(
@ -120,7 +120,7 @@ public final class OpenGroupManagerV2 : NSObject {
// TODO: Need to test this // TODO: Need to test this
// TODO: Clean this up (can we avoid the if/else with fancy promise wrangling?) // TODO: Clean this up (can we avoid the if/else with fancy promise wrangling?)
if let imageId: Int64 = room.imageId { if let imageId: Int64 = room.imageId {
OpenGroupAPIV2.roomImage(imageId, for: room.token, on: server) OpenGroupAPI.roomImage(imageId, for: room.token, on: server)
.done(on: DispatchQueue.global(qos: .userInitiated)) { data in .done(on: DispatchQueue.global(qos: .userInitiated)) { data in
storage.write { transaction in storage.write { transaction in
// Update the thread // Update the thread
@ -176,7 +176,7 @@ public final class OpenGroupManagerV2 : NSObject {
Storage.shared.removeReceivedMessageTimestamps(messageTimestamps, using: transaction) Storage.shared.removeReceivedMessageTimestamps(messageTimestamps, using: transaction)
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.legacyDeleteAuthToken(for: openGroup.room, on: openGroup.server) let _ = OpenGroupAPI.legacyDeleteAuthToken(for: openGroup.room, on: openGroup.server)
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)

View file

@ -4,7 +4,7 @@ import Foundation
import Sodium import Sodium
import SessionSnodeKit import SessionSnodeKit
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public struct Dependencies { public struct Dependencies {
let api: OnionRequestAPIType.Type let api: OnionRequestAPIType.Type
let storage: SessionMessagingKitStorageProtocol let storage: SessionMessagingKitStorageProtocol

View file

@ -2,196 +2,210 @@
import Foundation import Foundation
public enum Endpoint: Hashable { extension OpenGroupAPI {
// Utility public enum Endpoint: Hashable {
// Utility
case onion
case batch
case sequence
case capabilities
// Rooms
case rooms
case room(String)
case roomPollInfo(String, Int64)
// Messages
case roomMessage(String)
case roomMessageIndividual(String, String)
case roomMessagesRecent(String)
case roomMessagesBefore(String, id: Int64)
case roomMessagesSince(String, seqNo: Int64)
// Pinning
case roomPinMessage(String, id: Int64)
case roomUnpinMessage(String, id: Int64)
case roomUnpinAll(String)
// Files
case roomFile(String)
case roomFileJson(String)
case roomFileIndividual(String, Int64)
case roomFileIndividualJson(String, Int64)
// Inbox (Message Requests)
case inbox
case inboxSince(id: Int64)
case inboxFor(sessionId: String)
// Users
case userBan(String)
case userUnban(String)
case userPermission(String)
case userModerator(String)
case userDeleteMessages(String)
// Legacy endpoints (to be deprecated and removed)
@available(*, deprecated, message: "Use v4 endpoint") case legacyFiles
@available(*, deprecated, message: "Use v4 endpoint") case legacyFile(UInt64)
@available(*, deprecated, message: "Use v4 endpoint") case legacyMessages
@available(*, deprecated, message: "Use v4 endpoint") case legacyMessagesForServer(Int64)
@available(*, deprecated, message: "Use v4 endpoint") case legacyDeletedMessages
@available(*, deprecated, message: "Use v4 endpoint") case legacyModerators
@available(*, deprecated, message: "Use v4 endpoint") case legacyBlockList
@available(*, deprecated, message: "Use v4 endpoint") case legacyBlockListIndividual(String)
@available(*, deprecated, message: "Use v4 endpoint") case legacyBanAndDeleteAll
@available(*, deprecated, message: "Use v4 endpoint") case legacyCompactPoll(legacyAuth: Bool)
@available(*, deprecated, message: "Use request signing") case legacyAuthToken(legacyAuth: Bool)
@available(*, deprecated, message: "Use request signing") case legacyAuthTokenChallenge(legacyAuth: Bool)
@available(*, deprecated, message: "Use request signing") case legacyAuthTokenClaim(legacyAuth: Bool)
@available(*, deprecated, message: "Use v4 endpoint") case legacyRooms
@available(*, deprecated, message: "Use v4 endpoint") case legacyRoomInfo(String)
@available(*, deprecated, message: "Use v4 endpoint") case legacyRoomImage(String)
@available(*, deprecated, message: "Use v4 endpoint") case legacyMemberCount(legacyAuth: Bool)
var path: String {
switch self {
// Utility
case .onion: return "oxen/v4/lsrpc"
case .batch: return "batch"
case .sequence: return "sequence"
case .capabilities: return "capabilities"
// Rooms
case .rooms: return "rooms"
case .room(let roomToken): return "room/\(roomToken)"
case .roomPollInfo(let roomToken, let infoUpdated): return "room/\(roomToken)/pollInfo/\(infoUpdated)"
// Messages
case .roomMessage(let roomToken):
return "room/\(roomToken)/message"
case .roomMessageIndividual(let roomToken, let messageId):
return "room/\(roomToken)/message/\(messageId)"
case .roomMessagesRecent(let roomToken):
return "room/\(roomToken)/messages/recent"
case .roomMessagesBefore(let roomToken, let messageId):
return "room/\(roomToken)/messages/before/\(messageId)"
case .roomMessagesSince(let roomToken, let seqNo):
return "room/\(roomToken)/messages/since/\(seqNo)"
// Pinning
case .roomPinMessage(let roomToken, let messageId):
return "room/\(roomToken)/pin/\(messageId)"
case .roomUnpinMessage(let roomToken, let messageId):
return "room/\(roomToken)/unpin/\(messageId)"
case .roomUnpinAll(let roomToken):
return "room/\(roomToken)/unpin/all"
// Files
case .roomFile(let roomToken): return "room/\(roomToken)/file"
case .roomFileJson(let roomToken): return "room/\(roomToken)/fileJSON"
case .roomFileIndividual(let roomToken, let fileId):
// Note: The 'fileName' value is ignored by the server and is only used to distinguish
// this from the 'Json' variant
let fileName: String = ""
return "room/\(roomToken)/file/\(fileId)/\(fileName)"
case .roomFileIndividualJson(let roomToken, let fileId):
return "room/\(roomToken)/file/\(fileId)"
// Inbox (Message Requests)
case onion case .inbox: return "inbox"
case batch case .inboxSince(let id): return "inbox/\(id)"
case sequence case .inboxFor(let sessionId): return "inbox/\(sessionId)"
case capabilities
// Rooms
case rooms
case room(String)
case roomPollInfo(String, Int64)
// Messages
case roomMessage(String)
case roomMessageIndividual(String, String)
case roomMessagesRecent(String)
case roomMessagesBefore(String, id: Int64)
case roomMessagesSince(String, seqNo: Int64)
// Pinning
case roomPinMessage(String, id: Int64)
case roomUnpinMessage(String, id: Int64)
case roomUnpinAll(String)
// Files
case roomFile(String)
case roomFileJson(String)
case roomFileIndividual(String, Int64)
case roomFileIndividualJson(String, Int64)
// Users
case userBan(String)
case userUnban(String)
case userPermission(String)
case userModerator(String)
case userDeleteMessages(String)
// Legacy endpoints (to be deprecated and removed)
@available(*, deprecated, message: "Use v4 endpoint") case legacyFiles
@available(*, deprecated, message: "Use v4 endpoint") case legacyFile(UInt64)
@available(*, deprecated, message: "Use v4 endpoint") case legacyMessages
@available(*, deprecated, message: "Use v4 endpoint") case legacyMessagesForServer(Int64)
@available(*, deprecated, message: "Use v4 endpoint") case legacyDeletedMessages
@available(*, deprecated, message: "Use v4 endpoint") case legacyModerators
@available(*, deprecated, message: "Use v4 endpoint") case legacyBlockList
@available(*, deprecated, message: "Use v4 endpoint") case legacyBlockListIndividual(String)
@available(*, deprecated, message: "Use v4 endpoint") case legacyBanAndDeleteAll
@available(*, deprecated, message: "Use v4 endpoint") case legacyCompactPoll(legacyAuth: Bool)
@available(*, deprecated, message: "Use request signing") case legacyAuthToken(legacyAuth: Bool)
@available(*, deprecated, message: "Use request signing") case legacyAuthTokenChallenge(legacyAuth: Bool)
@available(*, deprecated, message: "Use request signing") case legacyAuthTokenClaim(legacyAuth: Bool)
@available(*, deprecated, message: "Use v4 endpoint") case legacyRooms
@available(*, deprecated, message: "Use v4 endpoint") case legacyRoomInfo(String)
@available(*, deprecated, message: "Use v4 endpoint") case legacyRoomImage(String)
@available(*, deprecated, message: "Use v4 endpoint") case legacyMemberCount(legacyAuth: Bool)
var path: String {
switch self {
// Utility
case .onion: return "oxen/v4/lsrpc"
case .batch: return "batch"
case .sequence: return "sequence"
case .capabilities: return "capabilities"
// Rooms // Users
case .rooms: return "rooms" case .userBan(let sessionId): return "user/\(sessionId)/ban"
case .room(let roomToken): return "room/\(roomToken)" case .userUnban(let sessionId): return "user/\(sessionId)/unban"
case .roomPollInfo(let roomToken, let infoUpdated): return "room/\(roomToken)/pollInfo/\(infoUpdated)" case .userPermission(let sessionId): return "user/\(sessionId)/permission"
case .userModerator(let sessionId): return "user/\(sessionId)/moderator"
case .userDeleteMessages(let sessionId): return "user/\(sessionId)/deleteMessages"
// Messages // 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 .roomMessage(let roomToken):
return "room/\(roomToken)/message"
case .legacyFiles: return "legacy/files"
case .legacyFile(let fileId): return "legacy/files/\(fileId)"
case .roomMessageIndividual(let roomToken, let messageId): case .legacyMessages: return "legacy/messages"
return "room/\(roomToken)/message/\(messageId)" case .legacyMessagesForServer(let serverId): return "legacy/messages/\(serverId)"
case .legacyDeletedMessages: return "legacy/deleted_messages"
case .roomMessagesRecent(let roomToken):
return "room/\(roomToken)/messages/recent" case .legacyModerators: return "legacy/moderators"
case .legacyBlockList: return "legacy/block_list"
case .legacyBlockListIndividual(let publicKey): return "legacy/block_list/\(publicKey)"
case .legacyBanAndDeleteAll: return "legacy/ban_and_delete_all"
case .roomMessagesBefore(let roomToken, let messageId): case .legacyCompactPoll(let useLegacyAuth):
return "room/\(roomToken)/messages/before/\(messageId)" return "\(useLegacyAuth ? "" : "legacy/")compact_poll"
case .roomMessagesSince(let roomToken, let seqNo): case .legacyAuthToken(let useLegacyAuth):
return "room/\(roomToken)/messages/since/\(seqNo)" return "\(useLegacyAuth ? "" : "legacy/")auth_token"
// Pinning case .legacyAuthTokenChallenge(let useLegacyAuth):
return "\(useLegacyAuth ? "" : "legacy/")auth_token_challenge"
case .roomPinMessage(let roomToken, let messageId):
return "room/\(roomToken)/pin/\(messageId)" case .legacyAuthTokenClaim(let useLegacyAuth):
return "\(useLegacyAuth ? "" : "legacy/")claim_auth_token"
case .roomUnpinMessage(let roomToken, let messageId):
return "room/\(roomToken)/unpin/\(messageId)" case .legacyRooms: return "legacy/rooms"
case .legacyRoomInfo(let roomName): return "legacy/rooms/\(roomName)"
case .roomUnpinAll(let roomToken): case .legacyRoomImage(let roomName): return "legacy/rooms/\(roomName)/image"
return "room/\(roomToken)/unpin/all"
case .legacyMemberCount(let useLegacyAuth):
// Files return "\(useLegacyAuth ? "" : "legacy/")member_count"
}
case .roomFile(let roomToken): return "room/\(roomToken)/file"
case .roomFileJson(let roomToken): return "room/\(roomToken)/fileJSON"
case .roomFileIndividual(let roomToken, let fileId):
// Note: The 'fileName' value is ignored by the server and is only used to distinguish
// this from the 'Json' variant
let fileName: String = ""
return "room/\(roomToken)/file/\(fileId)/\(fileName)"
case .roomFileIndividualJson(let roomToken, let fileId):
return "room/\(roomToken)/file/\(fileId)"
// Users
case .userBan(let sessionId): return "user/\(sessionId)/ban"
case .userUnban(let sessionId): return "user/\(sessionId)/unban"
case .userPermission(let sessionId): return "user/\(sessionId)/permission"
case .userModerator(let sessionId): return "user/\(sessionId)/moderator"
case .userDeleteMessages(let sessionId): return "user/\(sessionId)/deleteMessages"
// 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 .legacyFiles: return "legacy/files"
case .legacyFile(let fileId): return "legacy/files/\(fileId)"
case .legacyMessages: return "legacy/messages"
case .legacyMessagesForServer(let serverId): return "legacy/messages/\(serverId)"
case .legacyDeletedMessages: return "legacy/deleted_messages"
case .legacyModerators: return "legacy/moderators"
case .legacyBlockList: return "legacy/block_list"
case .legacyBlockListIndividual(let publicKey): return "legacy/block_list/\(publicKey)"
case .legacyBanAndDeleteAll: return "legacy/ban_and_delete_all"
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 .legacyRooms: return "legacy/rooms"
case .legacyRoomInfo(let roomName): return "legacy/rooms/\(roomName)"
case .legacyRoomImage(let roomName): return "legacy/rooms/\(roomName)/image"
case .legacyMemberCount(let useLegacyAuth):
return "\(useLegacyAuth ? "" : "legacy/")member_count"
} }
}
var useLegacyAuth: Bool {
var useLegacyAuth: Bool { switch self {
switch self { // File upload/download should use legacy auth
// File upload/download should use legacy auth case .legacyFiles, .legacyFile, .legacyMessages,
case .legacyFiles, .legacyFile, .legacyMessages, .legacyMessagesForServer, .legacyDeletedMessages,
.legacyMessagesForServer, .legacyDeletedMessages, .legacyModerators, .legacyBlockList,
.legacyModerators, .legacyBlockList, .legacyBlockListIndividual, .legacyBanAndDeleteAll:
.legacyBlockListIndividual, .legacyBanAndDeleteAll: return true
return true
case .legacyCompactPoll(let useLegacyAuth),
.legacyAuthToken(let useLegacyAuth),
.legacyAuthTokenChallenge(let useLegacyAuth),
.legacyAuthTokenClaim(let useLegacyAuth),
.legacyMemberCount(let useLegacyAuth):
return useLegacyAuth
case .legacyRooms, .legacyRoomInfo, .legacyRoomImage:
return true
case .legacyCompactPoll(let useLegacyAuth), default: return false
.legacyAuthToken(let useLegacyAuth), }
.legacyAuthTokenChallenge(let useLegacyAuth),
.legacyAuthTokenClaim(let useLegacyAuth),
.legacyMemberCount(let useLegacyAuth):
return useLegacyAuth
case .legacyRooms, .legacyRoomInfo, .legacyRoomImage:
return true
default: return false
} }
} }
} }

View file

@ -2,7 +2,7 @@
import Foundation import Foundation
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public enum Error: LocalizedError { public enum Error: LocalizedError {
case generic case generic
case parsingFailed case parsingFailed

View file

@ -10,7 +10,7 @@ extension NonceGenerator16ByteType {
} }
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public class NonceGenerator16Byte: NonceGenerator, NonceGenerator16ByteType { public class NonceGenerator16Byte: NonceGenerator, NonceGenerator16ByteType {
public var NonceBytes: Int { 16 } public var NonceBytes: Int { 16 }

View file

@ -3,7 +3,7 @@
import Foundation import Foundation
import Sodium import Sodium
extension OpenGroupAPIV2 { extension OpenGroupAPI {
public enum Personalization: String { public enum Personalization: String {
case sharedKeys = "sogs.shared_keys" case sharedKeys = "sogs.shared_keys"
case authHeader = "sogs.auth_header" case authHeader = "sogs.auth_header"

View file

@ -3,7 +3,7 @@
import Foundation import Foundation
import SessionUtilitiesKit import SessionUtilitiesKit
extension OpenGroupAPIV2 { extension OpenGroupAPI {
struct Request { struct Request {
let method: HTTP.Verb let method: HTTP.Verb
let server: String let server: String

View file

@ -373,7 +373,7 @@ public final class MessageSender : NSObject {
preconditionFailure() preconditionFailure()
} }
OpenGroupAPIV2 OpenGroupAPI
.send( .send(
plaintext, plaintext,
to: room, to: room,

View file

@ -48,13 +48,13 @@ public final class OpenGroupPollerV2 : NSObject {
let (promise, seal) = Promise<Void>.pending() let (promise, seal) = Promise<Void>.pending()
promise.retainUntilComplete() promise.retainUntilComplete()
OpenGroupAPIV2.poll(server) OpenGroupAPI.poll(server)
.done(on: OpenGroupAPIV2.workQueue) { [weak self] response in .done(on: OpenGroupAPI.workQueue) { [weak self] response in
self?.isPolling = false self?.isPolling = false
self?.handlePollResponse(response, isBackgroundPoll: isBackgroundPoll) self?.handlePollResponse(response, isBackgroundPoll: isBackgroundPoll)
seal.fulfill(()) seal.fulfill(())
} }
.catch(on: OpenGroupAPIV2.workQueue) { [weak self] error in .catch(on: OpenGroupAPI.workQueue) { [weak self] error in
SNLog("Open group polling failed due to error: \(error).") SNLog("Open group polling failed due to error: \(error).")
self?.isPolling = false self?.isPolling = false
seal.fulfill(()) // The promise is just used to keep track of when we're done seal.fulfill(()) // The promise is just used to keep track of when we're done
@ -63,13 +63,13 @@ public final class OpenGroupPollerV2 : NSObject {
return promise return promise
} }
private func handlePollResponse(_ response: [Endpoint: (info: OnionRequestResponseInfoType, data: Codable)], isBackgroundPoll: Bool) { private func handlePollResponse(_ response: [OpenGroupAPI.Endpoint: (info: OnionRequestResponseInfoType, data: Codable)], isBackgroundPoll: Bool) {
let storage = SNMessagingKitConfiguration.shared.storage let storage = SNMessagingKitConfiguration.shared.storage
response.forEach { endpoint, response in response.forEach { endpoint, response in
switch endpoint { switch endpoint {
case .roomMessagesRecent(let roomToken), .roomMessagesBefore(let roomToken, _), .roomMessagesSince(let roomToken, _): case .roomMessagesRecent(let roomToken), .roomMessagesBefore(let roomToken, _), .roomMessagesSince(let roomToken, _):
guard let responseData: [OpenGroupAPIV2.Message] = response.data as? [OpenGroupAPIV2.Message] else { guard let responseData: [OpenGroupAPI.Message] = response.data as? [OpenGroupAPI.Message] else {
//SNLog("Open group polling failed due to error: \(error).") //SNLog("Open group polling failed due to error: \(error).")
return // TODO: Throw error? return // TODO: Throw error?
} }
@ -77,7 +77,7 @@ public final class OpenGroupPollerV2 : NSObject {
handleMessages(responseData, roomToken: roomToken, isBackgroundPoll: isBackgroundPoll, using: storage) handleMessages(responseData, roomToken: roomToken, isBackgroundPoll: isBackgroundPoll, using: storage)
case .roomPollInfo(let roomToken, _): case .roomPollInfo(let roomToken, _):
guard let responseData: OpenGroupAPIV2.RoomPollInfo = response.data as? OpenGroupAPIV2.RoomPollInfo else { guard let responseData: OpenGroupAPI.RoomPollInfo = response.data as? OpenGroupAPI.RoomPollInfo else {
//SNLog("Open group polling failed due to error: \(error).") //SNLog("Open group polling failed due to error: \(error).")
return // TODO: Throw error? return // TODO: Throw error?
} }
@ -92,10 +92,10 @@ public final class OpenGroupPollerV2 : NSObject {
// MARK: - Custom response handling // MARK: - Custom response handling
// TODO: Shift this logic to the OpenGroupManagerV2? (seems like the place it should belong?) // TODO: Shift this logic to the OpenGroupManagerV2? (seems like the place it should belong?)
private func handleMessages(_ messages: [OpenGroupAPIV2.Message], roomToken: String, isBackgroundPoll: Bool, using storage: SessionMessagingKitStorageProtocol) { private func handleMessages(_ messages: [OpenGroupAPI.Message], roomToken: String, isBackgroundPoll: Bool, using storage: SessionMessagingKitStorageProtocol) {
// 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).\(roomToken)" let openGroupID = "\(server).\(roomToken)"
let sortedMessages: [OpenGroupAPIV2.Message] = messages let sortedMessages: [OpenGroupAPI.Message] = messages
.sorted { lhs, rhs in lhs.seqNo < rhs.seqNo } .sorted { lhs, rhs in lhs.seqNo < rhs.seqNo }
storage.write { transaction in storage.write { transaction in
@ -140,18 +140,18 @@ public final class OpenGroupPollerV2 : NSObject {
} }
} }
private func handlePollInfo(_ pollInfo: OpenGroupAPIV2.RoomPollInfo, roomToken: String, isBackgroundPoll: Bool, using storage: SessionMessagingKitStorageProtocol) { private func handlePollInfo(_ pollInfo: OpenGroupAPI.RoomPollInfo, roomToken: String, isBackgroundPoll: Bool, using storage: SessionMessagingKitStorageProtocol) {
// TODO: Handle other properties??? // TODO: Handle other properties???
// - Moderators // - Moderators
OpenGroupAPIV2.moderators[server] = (OpenGroupAPIV2.moderators[server] ?? [:]) OpenGroupAPI.moderators[server] = (OpenGroupAPI.moderators[server] ?? [:])
.setting(roomToken, Set(pollInfo.moderators ?? [])) .setting(roomToken, Set(pollInfo.moderators ?? []))
} }
// MARK: - Legacy Handling // MARK: - Legacy Handling
private func handleCompactPollBody(_ body: OpenGroupAPIV2.LegacyCompactPollResponse.Result, isBackgroundPoll: Bool) { private func handleCompactPollBody(_ body: OpenGroupAPI.LegacyCompactPollResponse.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
@ -177,12 +177,12 @@ public final class OpenGroupPollerV2 : NSObject {
} }
// - Moderators // - Moderators
if var x = OpenGroupAPIV2.moderators[server] { if var x = OpenGroupAPI.moderators[server] {
x[body.room] = Set(body.moderators ?? []) x[body.room] = Set(body.moderators ?? [])
OpenGroupAPIV2.moderators[server] = x OpenGroupAPI.moderators[server] = x
} }
else { else {
OpenGroupAPIV2.moderators[server] = [ body.room : Set(body.moderators ?? []) ] OpenGroupAPI.moderators[server] = [ body.room : Set(body.moderators ?? []) ]
} }
// - Deletions // - Deletions

View file

@ -16,7 +16,7 @@ extension Promise where T == (OnionRequestResponseInfoType, Data?) {
func decoded<R: Decodable>(as type: R.Type, on queue: DispatchQueue? = nil, error: Error? = nil) -> Promise<(OnionRequestResponseInfoType, R)> { func decoded<R: Decodable>(as type: R.Type, on queue: DispatchQueue? = nil, error: Error? = nil) -> Promise<(OnionRequestResponseInfoType, R)> {
self.map(on: queue) { responseInfo, maybeData -> (OnionRequestResponseInfoType, R) in self.map(on: queue) { responseInfo, maybeData -> (OnionRequestResponseInfoType, R) in
guard let data: Data = maybeData else { guard let data: Data = maybeData else {
throw OpenGroupAPIV2.Error.parsingFailed throw OpenGroupAPI.Error.parsingFailed
} }
return (responseInfo, try data.decoded(as: type, customError: error)) return (responseInfo, try data.decoded(as: type, customError: error))

View file

@ -49,7 +49,7 @@ extension MessageSender {
stream, stream,
using: { data in using: { data in
// TODO: Update to non-legacy version // TODO: Update to non-legacy version
OpenGroupAPIV2.legacyUpload( OpenGroupAPI.legacyUpload(
data, data,
to: v2OpenGroup.room, to: v2OpenGroup.room,
on: v2OpenGroup.server on: v2OpenGroup.server
@ -96,7 +96,7 @@ extension MessageSender {
stream, stream,
using: { data in using: { data in
// TODO: Update to non-legacy version // TODO: Update to non-legacy version
OpenGroupAPIV2.legacyUpload( OpenGroupAPI.legacyUpload(
data, data,
to: v2OpenGroup.room, to: v2OpenGroup.room,
on: v2OpenGroup.server on: v2OpenGroup.server