Implement SessionSnodeKit & SessionProtocolKit conformances

This commit is contained in:
nielsandriesse 2020-11-12 09:30:03 +11:00
parent 3ef9a50ca6
commit 5d8d468826
10 changed files with 234 additions and 6 deletions

View File

@ -0,0 +1,7 @@
extension AppDelegate : SharedSenderKeysDelegate {
public func requestSenderKey(for groupPublicKey: String, senderPublicKey: String, using transaction: Any) {
ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction as! YapDatabaseReadWriteTransaction)
}
}

View File

@ -0,0 +1,11 @@
import SessionProtocolKit
import SessionSnodeKit
@objc(SNConfiguration)
final class Configuration : NSObject {
@objc func performMainSetup() {
SessionProtocolKit.configure(storage: Storage.shared, sharedSenderKeysDelegate: UIApplication.shared.delegate as! AppDelegate)
SessionSnodeKit.configure(storage: Storage.shared)
}
}

View File

@ -0,0 +1,24 @@
extension Storage : SessionProtocolKitStorageProtocol {
private func getClosedGroupRatchetCollection(_ collection: ClosedGroupRatchetCollectionType, for groupPublicKey: String) -> String {
switch collection {
case .old: return "LokiOldClosedGroupRatchetCollection.\(groupPublicKey)"
case .current: return "LokiClosedGroupRatchetCollection.\(groupPublicKey)"
}
}
public func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType = .current) -> ClosedGroupRatchet? {
let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey)
var result: ClosedGroupRatchet?
Storage.read { transaction in
result = transaction.object(forKey: senderPublicKey, inCollection: collection) as? ClosedGroupRatchet
}
return result
}
public func setClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, in collection: ClosedGroupRatchetCollectionType = .current, using transaction: Any) {
let collection = getClosedGroupRatchetCollection(collection, for: groupPublicKey)
(transaction as! YapDatabaseReadWriteTransaction).setObject(ratchet, forKey: senderPublicKey, inCollection: collection)
}
}

View File

@ -0,0 +1,153 @@
extension Storage : SessionSnodeKitStorageProtocol {
// MARK: Onion Request Paths
internal static let onionRequestPathCollection = "LokiOnionRequestPathCollection"
public func getOnionRequestPaths() -> [OnionRequestAPI.Path] {
let collection = Storage.onionRequestPathCollection
var result: [OnionRequestAPI.Path] = []
Storage.read { transaction in
if
let path0Snode0 = transaction.object(forKey: "0-0", inCollection: collection) as? Snode,
let path0Snode1 = transaction.object(forKey: "0-1", inCollection: collection) as? Snode,
let path0Snode2 = transaction.object(forKey: "0-2", inCollection: collection) as? Snode {
result.append([ path0Snode0, path0Snode1, path0Snode2 ])
if
let path1Snode0 = transaction.object(forKey: "1-0", inCollection: collection) as? Snode,
let path1Snode1 = transaction.object(forKey: "1-1", inCollection: collection) as? Snode,
let path1Snode2 = transaction.object(forKey: "1-2", inCollection: collection) as? Snode {
result.append([ path1Snode0, path1Snode1, path1Snode2 ])
}
}
}
return result
}
public func setOnionRequestPaths(to paths: [OnionRequestAPI.Path], using transaction: Any) {
let collection = Storage.onionRequestPathCollection
// FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this.
clearOnionRequestPaths(using: transaction)
guard let transaction = transaction as? YapDatabaseReadWriteTransaction else { return }
guard paths.count >= 1 else { return }
let path0 = paths[0]
guard path0.count == 3 else { return }
transaction.setObject(path0[0], forKey: "0-0", inCollection: collection)
transaction.setObject(path0[1], forKey: "0-1", inCollection: collection)
transaction.setObject(path0[2], forKey: "0-2", inCollection: collection)
guard paths.count >= 2 else { return }
let path1 = paths[1]
guard path1.count == 3 else { return }
transaction.setObject(path1[0], forKey: "1-0", inCollection: collection)
transaction.setObject(path1[1], forKey: "1-1", inCollection: collection)
transaction.setObject(path1[2], forKey: "1-2", inCollection: collection)
}
func clearOnionRequestPaths(using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.onionRequestPathCollection)
}
// MARK: Snode Pool
public func getSnodePool() -> Set<Snode> {
var result: Set<Snode> = []
Storage.read { transaction in
transaction.enumerateKeysAndObjects(inCollection: Storage.snodePoolCollection) { _, object, _ in
guard let snode = object as? Snode else { return }
result.insert(snode)
}
}
return result
}
public func setSnodePool(to snodePool: Set<Snode>, using transaction: Any) {
clearSnodePool(in: transaction)
snodePool.forEach { snode in
(transaction as! YapDatabaseReadWriteTransaction).setObject(snode, forKey: snode.description, inCollection: Storage.snodePoolCollection)
}
}
func clearSnodePool(in transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: Storage.snodePoolCollection)
}
// MARK: Swarm
public func getSwarm(for publicKey: String) -> Set<Snode> {
var result: Set<Snode> = []
let collection = Storage.getSwarmCollection(for: publicKey)
Storage.read { transaction in
transaction.enumerateKeysAndObjects(inCollection: collection) { _, object, _ in
guard let snode = object as? Snode else { return }
result.insert(snode)
}
}
return result
}
public func setSwarm(to swarm: Set<Snode>, for publicKey: String, using transaction: Any) {
clearSwarm(for: publicKey, in: transaction)
let collection = Storage.getSwarmCollection(for: publicKey)
swarm.forEach { snode in
(transaction as! YapDatabaseReadWriteTransaction).setObject(snode, forKey: snode.description, inCollection: collection)
}
}
func clearSwarm(for publicKey: String, in transaction: Any) {
let collection = Storage.getSwarmCollection(for: publicKey)
(transaction as! YapDatabaseReadWriteTransaction).removeAllObjects(inCollection: collection)
}
// MARK: Last Message Hash
private static let lastMessageHashCollection = "LokiLastMessageHashCollection"
func getLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String) -> JSON? {
let key = "\(snode.address):\(snode.port).\(publicKey)"
var result: JSON?
Storage.read { transaction in
result = transaction.object(forKey: key, inCollection: Storage.lastMessageHashCollection) as? JSON
}
if let result = result {
guard result["hash"] as? String != nil else { return nil }
guard result["expirationDate"] as? NSNumber != nil else { return nil }
}
return result
}
public func getLastMessageHash(for snode: Snode, associatedWith publicKey: String) -> String? {
return getLastMessageHashInfo(for: snode, associatedWith: publicKey)?["hash"] as? String
}
public func setLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String, to lastMessageHashInfo: JSON, using transaction: Any) {
let key = "\(snode.address):\(snode.port).\(publicKey)"
guard lastMessageHashInfo.count == 2 && lastMessageHashInfo["hash"] as? String != nil && lastMessageHashInfo["expirationDate"] as? NSNumber != nil else { return }
(transaction as! YapDatabaseReadWriteTransaction).setObject(lastMessageHashInfo, forKey: key, inCollection: Storage.lastMessageHashCollection)
}
public func pruneLastMessageHashInfoIfExpired(for snode: Snode, associatedWith publicKey: String, using transaction: Any) {
guard let lastMessageHashInfo = getLastMessageHashInfo(for: snode, associatedWith: publicKey),
(lastMessageHashInfo["hash"] as? String) != nil, let expirationDate = (lastMessageHashInfo["expirationDate"] as? NSNumber)?.uint64Value else { return }
let now = NSDate.millisecondTimestamp()
if now >= expirationDate {
removeLastMessageHashInfo(for: snode, associatedWith: publicKey, using: transaction)
}
}
func removeLastMessageHashInfo(for snode: Snode, associatedWith publicKey: String, using transaction: Any) {
let key = "\(snode.address):\(snode.port).\(publicKey)"
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: Storage.lastMessageHashCollection)
}
// MARK: Received Messages
private static let receivedMessagesCollection = "LokiReceivedMessagesCollection"
public func getReceivedMessages(for publicKey: String) -> Set<String> {
var result: Set<String>?
Storage.read { transaction in
result = transaction.object(forKey: publicKey, inCollection: Storage.receivedMessagesCollection) as? Set<String>
}
return result ?? []
}
public func setReceivedMessages(to receivedMessages: Set<String>, for publicKey: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(receivedMessages, forKey: publicKey, inCollection: Storage.receivedMessagesCollection)
}
}

View File

@ -0,0 +1,13 @@
extension Storage {
public static let shared = Storage()
public func with(_ work: @escaping (Any) -> Void) {
Storage.writeSync { work($0) }
}
public func getUserPublicKey() -> String? {
return OWSIdentityManager.shared().identityKeyPair()?.publicKey()?.toHexString()
}
}

View File

@ -8,7 +8,7 @@ public struct Configuration {
public enum SessionProtocolKit { // Just to make the external API nice
public static func configure(with configuration: Configuration) {
Configuration.shared = configuration
public static func configure(storage: SessionProtocolKitStorageProtocol, sharedSenderKeysDelegate: SharedSenderKeysDelegate) {
Configuration.shared = Configuration(storage: storage, sharedSenderKeysDelegate: sharedSenderKeysDelegate)
}
}

View File

@ -5,7 +5,7 @@ public enum ClosedGroupRatchetCollectionType {
public protocol SessionProtocolKitStorageProtocol {
func with(_ work: (Any) -> Void)
func with(_ work: @escaping (Any) -> Void)
func getClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, from collection: ClosedGroupRatchetCollectionType) -> ClosedGroupRatchet?
func setClosedGroupRatchet(for groupPublicKey: String, senderPublicKey: String, ratchet: ClosedGroupRatchet, in collection: ClosedGroupRatchetCollectionType, using transaction: Any)

View File

@ -7,7 +7,7 @@ public struct Configuration {
public enum SessionSnodeKit { // Just to make the external API nice
public static func configure(with configuration: Configuration) {
Configuration.shared = configuration
public static func configure(storage: SessionSnodeKitStorageProtocol) {
Configuration.shared = Configuration(storage: storage)
}
}

View File

@ -2,7 +2,7 @@ import SessionUtilitiesKit
public protocol SessionSnodeKitStorageProtocol {
func with(_ work: (Any) -> Void)
func with(_ work: @escaping (Any) -> Void)
func getUserPublicKey() -> String?
func getOnionRequestPaths() -> [OnionRequestAPI.Path]

View File

@ -1188,6 +1188,11 @@
C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; };
C3E7134F251C867C009649BB /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; };
C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; };
C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; };
C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; };
C3F0A608255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A607255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift */; };
C3F0A61A255C9902007BE2A3 /* Storage+SessionProtocolKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A619255C9902007BE2A3 /* Storage+SessionProtocolKit.swift */; };
C3F0A62C255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */; };
D2179CFC16BB0B3A0006F3AB /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */; };
D2179CFE16BB0B480006F3AB /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2179CFD16BB0B480006F3AB /* SystemConfiguration.framework */; };
D221A08E169C9E5E00537ABF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D221A08D169C9E5E00537ABF /* UIKit.framework */; };
@ -2579,6 +2584,11 @@
C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = "<group>"; };
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Shared.swift"; sourceTree = "<group>"; };
C3F0A607255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SessionSnodeKit.swift"; sourceTree = "<group>"; };
C3F0A619255C9902007BE2A3 /* Storage+SessionProtocolKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+SessionProtocolKit.swift"; sourceTree = "<group>"; };
C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+SharedSenderKeys.swift"; sourceTree = "<group>"; };
C88965DE4F4EC4FC919BEC4E /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = "<group>"; };
CB3724C70247A916D43271FE /* Pods_Session.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Session.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
@ -4534,6 +4544,11 @@
isa = PBXGroup;
children = (
C3F0A58F255C8E3D007BE2A3 /* Meta */,
C3F0A62B255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift */,
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */,
C3F0A619255C9902007BE2A3 /* Storage+SessionProtocolKit.swift */,
C3F0A607255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift */,
C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */,
B8CCF63B239757C10091D419 /* Components */,
C31F812425258F9C00DD9FD9 /* Database */,
C32B405424A961E1001117B5 /* Dependencies */,
@ -6220,6 +6235,7 @@
B8CCF63723961D6D0091D419 /* NewPrivateChatVC.swift in Sources */,
4CC0B59C20EC5F2E00CF6EE0 /* ConversationConfigurationSyncOperation.swift in Sources */,
3461293E1FD1D72B00532771 /* ExperienceUpgradeFinder.swift in Sources */,
C3F0A61A255C9902007BE2A3 /* Storage+SessionProtocolKit.swift in Sources */,
34C4E2582118957600BEA353 /* WebRTCProto.swift in Sources */,
C396DAF12518408B00FF6DC5 /* EnumeratedView.swift in Sources */,
34D1F0BD1F8D108C0066283D /* AttachmentUploadView.m in Sources */,
@ -6311,6 +6327,7 @@
C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */,
C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */,
45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */,
C3F0A62C255C9937007BE2A3 /* AppDelegate+SharedSenderKeys.swift in Sources */,
452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */,
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */,
34D1F0881F8678AA0066283D /* ConversationViewLayout.m in Sources */,
@ -6333,6 +6350,7 @@
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */,
C369549D24D27A3500CEB4E3 /* MultiDeviceRemovalSheet.swift in Sources */,
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */,
C3F0A608255C98A6007BE2A3 /* Storage+SessionSnodeKit.swift in Sources */,
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */,
2400888E239F30A600305217 /* SessionRestorationView.swift in Sources */,
@ -6385,11 +6403,13 @@
34277A5E20751BDC006049F2 /* OWSQuotedMessageView.m in Sources */,
458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */,
45DDA6242090CEB500DE97F8 /* ConversationHeaderView.swift in Sources */,
C3F0A5FE255C988A007BE2A3 /* Storage+Shared.swift in Sources */,
B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */,
3488F9362191CC4000E524CC /* ConversationMediaView.swift in Sources */,
45F32C242057297A00A300D5 /* MessageDetailViewController.swift in Sources */,
C396DAEF2518408B00FF6DC5 /* ParsingState.swift in Sources */,
3496955C219B605E00DCFE74 /* ImagePickerController.swift in Sources */,
C3F0A5EC255C970D007BE2A3 /* Configuration.swift in Sources */,
34D1F0841F8678AA0066283D /* ConversationInputToolbar.m in Sources */,
457F671B20746193000EABCD /* QuotedReplyPreview.swift in Sources */,
C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */,