Re-added the transaction requirement when generating the current config message

pull/604/head
Morgan Pretty 3 years ago
parent 29c53223e0
commit 212c5e87aa

@ -7,10 +7,11 @@ extension AppDelegate {
guard Storage.shared.getUser()?.name != nil else { return }
let userDefaults = UserDefaults.standard
let lastSync = userDefaults[.lastConfigurationSync] ?? .distantPast
guard Date().timeIntervalSince(lastSync) > 7 * 24 * 60 * 60,
let configurationMessage = ConfigurationMessage.getCurrent() else { return } // Sync every 2 days
guard Date().timeIntervalSince(lastSync) > 7 * 24 * 60 * 60 else { return } // Sync every 2 days
let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
Storage.shared.write { transaction in
Storage.write { transaction in
guard let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else { return }
let job = MessageSendJob(message: configurationMessage, destination: destination)
JobQueue.shared.add(job, using: transaction)
}
@ -28,7 +29,7 @@ extension AppDelegate {
// Note: SQLite only supports a single write thread so we can be sure this will retrieve the most up-to-date data
Storage.writeSync { transaction in
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent() else {
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
seal.fulfill(())
return
}

@ -10,13 +10,19 @@ extension Storage {
private static let closedGroupZombieMembersCollection = "SNClosedGroupZombieMembersCollection"
public func getClosedGroupEncryptionKeyPairs(for groupPublicKey: String) -> [ECKeyPair] {
var result: [ECKeyPair] = []
Storage.read { transaction in
result = self.getClosedGroupEncryptionKeyPairs(for: groupPublicKey, using: transaction)
}
return result
}
public func getClosedGroupEncryptionKeyPairs(for groupPublicKey: String, using transaction: YapDatabaseReadTransaction) -> [ECKeyPair] {
let collection = Storage.getClosedGroupEncryptionKeyPairCollection(for: groupPublicKey)
var timestampsAndKeyPairs: [(timestamp: Double, keyPair: ECKeyPair)] = []
Storage.read { transaction in
transaction.enumerateKeysAndObjects(inCollection: collection) { key, object, _ in
guard let timestamp = Double(key), let keyPair = object as? ECKeyPair else { return }
timestampsAndKeyPairs.append((timestamp, keyPair))
}
transaction.enumerateKeysAndObjects(inCollection: collection) { key, object, _ in
guard let timestamp = Double(key), let keyPair = object as? ECKeyPair else { return }
timestampsAndKeyPairs.append((timestamp, keyPair))
}
return timestampsAndKeyPairs.sorted { $0.timestamp < $1.timestamp }.map { $0.keyPair }
}
@ -24,6 +30,10 @@ extension Storage {
public func getLatestClosedGroupEncryptionKeyPair(for groupPublicKey: String) -> ECKeyPair? {
return getClosedGroupEncryptionKeyPairs(for: groupPublicKey).last
}
public func getLatestClosedGroupEncryptionKeyPair(for groupPublicKey: String, using transaction: YapDatabaseReadTransaction) -> ECKeyPair? {
return getClosedGroupEncryptionKeyPairs(for: groupPublicKey, using: transaction).last
}
public func addClosedGroupEncryptionKeyPair(_ keyPair: ECKeyPair, for groupPublicKey: String, using transaction: Any) {
let collection = Storage.getClosedGroupEncryptionKeyPairCollection(for: groupPublicKey)
@ -39,11 +49,15 @@ extension Storage {
public func getUserClosedGroupPublicKeys() -> Set<String> {
var result: Set<String> = []
Storage.read { transaction in
result = Set(transaction.allKeys(inCollection: Storage.closedGroupPublicKeyCollection))
result = self.getUserClosedGroupPublicKeys(using: transaction)
}
return result
}
public func getUserClosedGroupPublicKeys(using transaction: YapDatabaseReadTransaction) -> Set<String> {
return Set(transaction.allKeys(inCollection: Storage.closedGroupPublicKeyCollection))
}
public func addClosedGroupPublicKey(_ groupPublicKey: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(groupPublicKey, forKey: groupPublicKey, inCollection: Storage.closedGroupPublicKeyCollection)
}
@ -81,4 +95,8 @@ extension Storage {
public func isClosedGroup(_ publicKey: String) -> Bool {
getUserClosedGroupPublicKeys().contains(publicKey)
}
public func isClosedGroup(_ publicKey: String, using transaction: YapDatabaseReadTransaction) -> Bool {
getUserClosedGroupPublicKeys(using: transaction).contains(publicKey)
}
}

@ -36,12 +36,21 @@ extension Storage {
}
@objc public func getUser() -> Contact? {
return getUser(using: nil)
}
public func getUser(using transaction: YapDatabaseReadTransaction?) -> Contact? {
let userPublicKey = getUserHexEncodedPublicKey()
var result: Contact?
Storage.read { transaction in
if let transaction = transaction {
result = Storage.shared.getContact(with: userPublicKey, using: transaction)
}
else {
Storage.read { transaction in
result = Storage.shared.getContact(with: userPublicKey, using: transaction)
}
}
return result
}
}

@ -2,9 +2,9 @@ import SessionUtilitiesKit
extension ConfigurationMessage {
public static func getCurrent() -> ConfigurationMessage? {
public static func getCurrent(with transaction: YapDatabaseReadTransaction) -> ConfigurationMessage? {
let storage = Storage.shared
guard let user = storage.getUser() else { return nil }
guard let user = storage.getUser(using: transaction) else { return nil }
let displayName = user.name
let profilePictureURL = user.profilePictureURL
@ -13,83 +13,84 @@ extension ConfigurationMessage {
var openGroups: Set<String> = []
var contacts: Set<ConfigurationMessage.Contact> = []
Storage.read { transaction in
TSGroupThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSGroupThread else { return }
switch thread.groupModel.groupType {
case .closedGroup:
guard thread.isCurrentUserMemberInGroup() else { return }
let groupID = thread.groupModel.groupId
let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID)
guard storage.isClosedGroup(groupPublicKey), let encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey) else {
return
}
let closedGroup = ClosedGroup(
publicKey: groupPublicKey,
name: (thread.groupModel.groupName ?? ""),
encryptionKeyPair: encryptionKeyPair,
members: Set(thread.groupModel.groupMemberIds),
admins: Set(thread.groupModel.groupAdminIds),
expirationTimer: thread.disappearingMessagesDuration(with: transaction)
)
closedGroups.insert(closedGroup)
case .openGroup:
if let threadId: String = thread.uniqueId, let v2OpenGroup = storage.getV2OpenGroup(for: threadId) {
openGroups.insert("\(v2OpenGroup.server)/\(v2OpenGroup.room)?public_key=\(v2OpenGroup.publicKey)")
}
default: break
}
}
let currentUserPublicKey: String = getUserHexEncodedPublicKey()
TSGroupThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSGroupThread else { return }
contacts = storage.getAllContacts(with: transaction)
.filter { contact -> Bool in
let threadID = TSContactThread.threadID(fromContactSessionID: contact.sessionID)
switch thread.groupModel.groupType {
case .closedGroup:
guard thread.isCurrentUserMemberInGroup() else { return }
return (
// Skip the current user
contact.sessionID != currentUserPublicKey &&
// Contacts which have visible threads
TSContactThread.fetch(uniqueId: threadID, transaction: transaction)?.shouldBeVisible == true && (
// Include already approved contacts
contact.isApproved ||
contact.didApproveMe ||
// Sync blocked contacts
SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID)
)
)
}
.map { contact -> ConfigurationMessage.Contact in
// Can just default the 'hasX' values to true as they will be set to this
// when converting to proto anyway
let profilePictureURL = contact.profilePictureURL
let profileKey = contact.profileEncryptionKey?.keyData
let groupID = thread.groupModel.groupId
let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID)
return ConfigurationMessage.Contact(
publicKey: contact.sessionID,
displayName: (contact.name ?? contact.sessionID),
profilePictureURL: profilePictureURL,
profileKey: profileKey,
hasIsApproved: true,
isApproved: contact.isApproved,
hasIsBlocked: true,
isBlocked: SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID),
hasDidApproveMe: true,
didApproveMe: contact.didApproveMe
guard
storage.isClosedGroup(groupPublicKey, using: transaction),
let encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey, using: transaction)
else {
return
}
let closedGroup = ClosedGroup(
publicKey: groupPublicKey,
name: (thread.groupModel.groupName ?? ""),
encryptionKeyPair: encryptionKeyPair,
members: Set(thread.groupModel.groupMemberIds),
admins: Set(thread.groupModel.groupAdminIds),
expirationTimer: thread.disappearingMessagesDuration(with: transaction)
)
}
.asSet()
closedGroups.insert(closedGroup)
case .openGroup:
if let threadId: String = thread.uniqueId, let v2OpenGroup = storage.getV2OpenGroup(for: threadId) {
openGroups.insert("\(v2OpenGroup.server)/\(v2OpenGroup.room)?public_key=\(v2OpenGroup.publicKey)")
}
default: break
}
}
let currentUserPublicKey: String = getUserHexEncodedPublicKey()
contacts = storage.getAllContacts(with: transaction)
.filter { contact -> Bool in
let threadID = TSContactThread.threadID(fromContactSessionID: contact.sessionID)
return (
// Skip the current user
contact.sessionID != currentUserPublicKey &&
// Contacts which have visible threads
TSContactThread.fetch(uniqueId: threadID, transaction: transaction)?.shouldBeVisible == true && (
// Include already approved contacts
contact.isApproved ||
contact.didApproveMe ||
// Sync blocked contacts
SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID)
)
)
}
.map { contact -> ConfigurationMessage.Contact in
// Can just default the 'hasX' values to true as they will be set to this
// when converting to proto anyway
let profilePictureURL = contact.profilePictureURL
let profileKey = contact.profileEncryptionKey?.keyData
return ConfigurationMessage.Contact(
publicKey: contact.sessionID,
displayName: (contact.name ?? contact.sessionID),
profilePictureURL: profilePictureURL,
profileKey: profileKey,
hasIsApproved: true,
isApproved: contact.isApproved,
hasIsBlocked: true,
isBlocked: SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID),
hasDidApproveMe: true,
didApproveMe: contact.didApproveMe
)
}
.asSet()
return ConfigurationMessage(
displayName: displayName,
profilePictureURL: profilePictureURL,

@ -827,12 +827,14 @@ extension MessageReceiver {
// a new configuration message (otherwise the `contact` will be loaded direct from the database and the
// `didApproveMe` value won't have been updated)
DispatchQueue.global(qos: .background).async {
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent() else {
return
Storage.write { transaction in
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
return
}
let destination: Message.Destination = Message.Destination.contact(publicKey: userPublicKey)
MessageSender.send(configurationMessage, to: destination, using: transaction).retainUntilComplete()
}
let destination: Message.Destination = Message.Destination.contact(publicKey: userPublicKey)
MessageSender.send(configurationMessage, to: destination, using: transaction).retainUntilComplete()
}
}

@ -17,15 +17,18 @@ public protocol SessionMessagingKitStorageProtocol {
func getUserKeyPair() -> ECKeyPair?
func getUserED25519KeyPair() -> Box.KeyPair?
func getUser() -> Contact?
func getUser(using transaction: YapDatabaseReadTransaction?) -> Contact?
func getAllContacts() -> Set<Contact>
func getAllContacts(with transaction: YapDatabaseReadTransaction) -> Set<Contact>
// MARK: - Closed Groups
func getUserClosedGroupPublicKeys() -> Set<String>
func getUserClosedGroupPublicKeys(using transaction: YapDatabaseReadTransaction) -> Set<String>
func getZombieMembers(for groupPublicKey: String) -> Set<String>
func setZombieMembers(for groupPublicKey: String, to zombies: Set<String>, using transaction: Any)
func isClosedGroup(_ publicKey: String) -> Bool
func isClosedGroup(_ publicKey: String, using transaction: YapDatabaseReadTransaction) -> Bool
// MARK: - Jobs

Loading…
Cancel
Save