This commit is contained in:
nielsandriesse 2020-05-02 10:28:04 +10:00
parent 96331ecdd5
commit 0d48031e9c
4 changed files with 60 additions and 66 deletions

View file

@ -920,7 +920,7 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
TSGroupThread *groupThread = (TSGroupThread *)thread;
NSData *groupId = groupThread.groupModel.groupId;
return [self isGroupIdInProfileWhitelist:groupId];
} else if ([LKFriendRequestProtocol isFriendsWithLinkedDevicesOfHexEncodedPublicKey:thread.contactIdentifier]) {
} else if ([LKFriendRequestProtocol isFriendsWithAnyLinkedDeviceOfHexEncodedPublicKey:thread.contactIdentifier]) {
return true;
} else {
NSString *recipientId = thread.contactIdentifier;

View file

@ -724,7 +724,7 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
{
// If we're friends with the person then we don't need to remove any friend request messages
if (self.isGroupThread) { return; }
if ([LKFriendRequestProtocol isFriendsWithLinkedDevicesOfHexEncodedPublicKey:self.contactIdentifier]) { return; }
if ([LKFriendRequestProtocol isFriendsWithAnyLinkedDeviceOfHexEncodedPublicKey:self.contactIdentifier]) { return; }
NSMutableArray<NSString *> *idsToRemove = [NSMutableArray new];
__block TSMessage *_Nullable messageToKeep = nil; // We want to keep this interaction and not remove it

View file

@ -15,44 +15,43 @@ public final class FriendRequestProtocol : NSObject {
internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() }
// MARK: - Enums
// FIXME: Better naming :(
@objc public enum FriendRequestUIState : Int {
// MARK: - Friend Request UI Status
@objc public enum FriendRequestUIStatus : Int {
case friends, received, sent, none
}
// MARK: - General
@objc(isFriendsWithLinkedDevicesOfHexEncodedPublicKey:)
public static func isFriendsWithLinkedDevices(of hexEncodedPublicKey: String) -> Bool {
var isFriends = false
@objc(isFriendsWithAnyLinkedDeviceOfHexEncodedPublicKey:)
public static func isFriendsWithAnyLinkedDevice(of hexEncodedPublicKey: String) -> Bool {
var result = false
storage.dbReadConnection.read { transaction in
let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: hexEncodedPublicKey, in: transaction)
let friendRequestStatuses = linkedDevices.map { device in
return storage.getFriendRequestStatus(for: device, transaction: transaction)
let friendRequestStatuses = linkedDevices.map {
storage.getFriendRequestStatus(for: $0, transaction: transaction)
}
isFriends = friendRequestStatuses.contains(where: { $0 == .friends })
result = friendRequestStatuses.contains { $0 == .friends }
}
return isFriends
return result
}
@objc(shouldInputBarBeEnabledForThread:)
public static func shouldInputBarBeEnabled(for thread: TSThread) -> Bool {
// Friend requests have nothing to do with groups, so if this isn't a contact thread the input bar should be enabled
guard let thread = thread as? TSContactThread else { return true }
// If this is a note to self, the input bar should be enabled
// If this is a note to self the input bar should be enabled
if thread.isNoteToSelf() { return true }
let contactID = thread.contactIdentifier()
var friendRequestStatuses: [LKFriendRequestStatus] = []
var linkedDeviceFriendRequestStatuses: [LKFriendRequestStatus] = []
storage.dbReadConnection.read { transaction in
let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: contactID, in: transaction)
friendRequestStatuses = linkedDevices.map { device in
return storage.getFriendRequestStatus(for: device, transaction: transaction)
linkedDeviceFriendRequestStatuses = linkedDevices.map {
storage.getFriendRequestStatus(for: $0, transaction: transaction)
}
}
// If the current user is friends with any of the other user's devices, the input bar should be enabled
if friendRequestStatuses.contains(where: { $0 == .friends }) { return true }
if linkedDeviceFriendRequestStatuses.contains(where: { $0 == .friends }) { return true }
// If no friend request has been sent, the input bar should be enabled
if friendRequestStatuses.allSatisfy({ $0 == .none || $0 == .requestExpired }) { return true }
if linkedDeviceFriendRequestStatuses.allSatisfy({ $0 == .none || $0 == .requestExpired }) { return true }
// There must be a pending friend request
return false
}
@ -64,50 +63,47 @@ public final class FriendRequestProtocol : NSObject {
// If this is a note to self, the attachment button should be enabled
if thread.isNoteToSelf() { return true }
let contactID = thread.contactIdentifier()
var friendRequestStatuses: [LKFriendRequestStatus] = []
var linkedDeviceFriendRequestStatuses: [LKFriendRequestStatus] = []
storage.dbReadConnection.read { transaction in
let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: contactID, in: transaction)
friendRequestStatuses = linkedDevices.map { device in
storage.getFriendRequestStatus(for: device, transaction: transaction)
linkedDeviceFriendRequestStatuses = linkedDevices.map {
storage.getFriendRequestStatus(for: $0, transaction: transaction)
}
}
// If the current user is friends with any of the other user's devices, the attachment button should be enabled
if friendRequestStatuses.contains(where: { $0 == .friends }) { return true }
// Otherwise don't allow attachments at all
if linkedDeviceFriendRequestStatuses.contains(where: { $0 == .friends }) { return true }
// Otherwise don't allow attachments
return false
}
@objc(getFriendRequestUIStateForThread:)
public static func getFriendRequestUIState(for thread: TSThread) -> FriendRequestUIState {
@objc(getFriendRequestUIStatusForThread:)
public static func getFriendRequestUIStatus(for thread: TSThread) -> FriendRequestUIStatus {
// Friend requests have nothing to do with groups
guard let thread = thread as? TSContactThread else { return .none }
// If this is a note to self then we don't want to show the friend request
if thread.isNoteToSelf() { return .none }
guard !thread.isNoteToSelf() else { return .none }
var friendRequestStatuses: [LKFriendRequestStatus] = []
storage.dbReadConnection.read { transaction in
let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: thread.contactIdentifier(), in: transaction)
friendRequestStatuses = linkedDevices.map { device in
return storage.getFriendRequestStatus(for: device, transaction: transaction)
friendRequestStatuses = linkedDevices.map {
storage.getFriendRequestStatus(for: $0, transaction: transaction)
}
}
if friendRequestStatuses.contains(where: { $0 == .friends }) { return .friends }
if friendRequestStatuses.contains(where: { $0 == .requestReceived }) { return .received }
if friendRequestStatuses.contains(where: { $0 == .requestSent }) { return .sent }
return .none
}
// MARK: - Sending
@objc(acceptFriendRequestFromHexEncodedPublicKey:using:)
public static func acceptFriendRequest(from hexEncodedPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
guard ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) else {
print("[Loki] Invalid Session ID: \(hexEncodedPublicKey).")
return
}
// Accept all outstanding friend requests associated with this user and try to establish sessions with the
// subset of their devices that haven't sent a friend request.
guard ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) else {
assertionFailure("Invalid session ID \(hexEncodedPublicKey)")
return;
}
let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: hexEncodedPublicKey, in: transaction)
for device in linkedDevices {
let friendRequestStatus = storage.getFriendRequestStatus(for: device, transaction: transaction)
@ -116,12 +112,13 @@ public final class FriendRequestProtocol : NSObject {
sendFriendRequestAcceptanceMessage(to: device, using: transaction)
} else if friendRequestStatus == .requestSent {
// We sent a friend request to this device before, how can we be sure that it hasn't expired?
// TODO: Shouldn't the status then be .expired?
} else if friendRequestStatus == .none || friendRequestStatus == .requestExpired {
// TODO: Need to track these so that we can expire them and resend incase the other user wasn't online after we sent
MultiDeviceProtocol.getAutoGeneratedMultiDeviceFRMessageSend(for: device, in: transaction) // NOT hexEncodedPublicKey
.done(on: OWSDispatch.sendingQueue()) { autoGeneratedFRMessageSend in
let messageSender = SSKEnvironment.shared.messageSender
messageSender.sendMessage(autoGeneratedFRMessageSend)
// TODO: We should track these so that we can expire them and resend if needed
MultiDeviceProtocol.getAutoGeneratedMultiDeviceFRMessageSend(for: device, in: transaction)
.done(on: OWSDispatch.sendingQueue()) { autoGeneratedFRMessageSend in
let messageSender = SSKEnvironment.shared.messageSender
messageSender.sendMessage(autoGeneratedFRMessageSend)
}
}
}
@ -130,10 +127,9 @@ public final class FriendRequestProtocol : NSObject {
@objc(sendFriendRequestAcceptanceMessageToHexEncodedPublicKey:using:)
public static func sendFriendRequestAcceptanceMessage(to hexEncodedPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
guard ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) else {
assertionFailure("Invalid session ID \(hexEncodedPublicKey)")
return;
print("[Loki] Invalid Session ID: \(hexEncodedPublicKey).")
return
}
let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction)
let ephemeralMessage = EphemeralMessage(in: thread)
let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue
@ -143,15 +139,14 @@ public final class FriendRequestProtocol : NSObject {
@objc(declineFriendRequestFromHexEncodedPublicKey:using:)
public static func declineFriendRequest(from hexEncodedPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
guard ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) else {
assertionFailure("Invalid session ID \(hexEncodedPublicKey)")
return;
print("[Loki] Invalid Session ID: \(hexEncodedPublicKey).")
return
}
let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: hexEncodedPublicKey, in: transaction)
for device in linkedDevices {
let friendRequestStatus = storage.getFriendRequestStatus(for: device, transaction: transaction)
// We only want to decline any incoming requests
if (friendRequestStatus == .requestReceived) {
// We only want to decline incoming requests
if friendRequestStatus == .requestReceived {
// Delete the pre key bundle for the given contact. This ensures that if we send a
// new message after this, it restarts the friend request process from scratch.
storage.removePreKeyBundle(forContact: device, transaction: transaction)
@ -160,28 +155,25 @@ public final class FriendRequestProtocol : NSObject {
}
}
@objc(sendingFriendRequestToHexEncodedPublicKey:transaction:)
public static func sendingFriendRequest(to hexEncodedPublicKey: String, transaction: YapDatabaseReadWriteTransaction) {
@objc(setFriendRequestStatusToSendingIfNeededForHexEncodedPublicKey:transaction:)
public static func setFriendRequestStatusToSendingIfNeeded(for hexEncodedPublicKey: String, transaction: YapDatabaseReadWriteTransaction) {
let friendRequestStatus = storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction)
if (friendRequestStatus == .none || friendRequestStatus == .requestExpired) {
storage.setFriendRequestStatus(.requestSending, for: hexEncodedPublicKey, transaction: transaction)
}
guard friendRequestStatus == .none || friendRequestStatus == .requestExpired else { return }
storage.setFriendRequestStatus(.requestSending, for: hexEncodedPublicKey, transaction: transaction)
}
@objc(sentFriendRequestToHexEncodedPublicKey:transaction:)
public static func sentFriendRequest(to hexEncodedPublicKey: String, transaction: YapDatabaseReadWriteTransaction) {
@objc(setFriendRequestStatusToSentIfNeededForHexEncodedPublicKey:transaction:)
public static func setFriendRequestStatusToSentIfNeeded(for hexEncodedPublicKey: String, transaction: YapDatabaseReadWriteTransaction) {
let friendRequestStatus = storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction)
if (friendRequestStatus == .none || friendRequestStatus == .requestExpired || friendRequestStatus == .requestSending) {
storage.setFriendRequestStatus(.requestSent, for: hexEncodedPublicKey, transaction: transaction)
}
guard friendRequestStatus == .none || friendRequestStatus == .requestExpired || friendRequestStatus == .requestSending else { return }
storage.setFriendRequestStatus(.requestSent, for: hexEncodedPublicKey, transaction: transaction)
}
@objc(failedToSendFriendRequestToHexEncodedPublicKey:transaction:)
public static func failedToSendFriendRequest(to hexEncodedPublicKey: String, transaction: YapDatabaseReadWriteTransaction) {
@objc(setFriendRequestStatusToFailedIfNeededForHexEncodedPublicKey:transaction:)
public static func setFriendRequestStatusToFailedIfNeeded(for hexEncodedPublicKey: String, transaction: YapDatabaseReadWriteTransaction) {
let friendRequestStatus = storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction)
if (friendRequestStatus == .requestSending) {
storage.setFriendRequestStatus(.none, for: hexEncodedPublicKey, transaction: transaction)
}
guard friendRequestStatus == .requestSending else { return }
storage.setFriendRequestStatus(.none, for: hexEncodedPublicKey, transaction: transaction)
}
// MARK: - Receiving
@ -212,7 +204,9 @@ public final class FriendRequestProtocol : NSObject {
if userLinkedDeviceHexEncodedPublicKeys.contains(hexEncodedPublicKey) { return true }
// Auto-accept if the user is friends with any of the sender's linked devices.
let senderLinkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: hexEncodedPublicKey, in: transaction)
if senderLinkedDevices.contains(where: { storage.getFriendRequestStatus(for: $0, transaction: transaction) == .friends }) {
if senderLinkedDevices.contains(where: {
storage.getFriendRequestStatus(for: $0, transaction: transaction) == .friends
}) {
return true
}
// We can't auto-accept

View file

@ -351,7 +351,7 @@ class FriendRequestProtocolTests : XCTestCase {
let bob = generateHexEncodedPublicKey()
let bobThread = createContactThread(for: bob)
let expectedStates: [LKFriendRequestStatus : FriendRequestProtocol.FriendRequestUIState] = [
let expectedStates: [LKFriendRequestStatus : FriendRequestProtocol.FriendRequestUIStatus] = [
.none: .none,
.requestExpired: .none,
.requestSending: .none,
@ -384,7 +384,7 @@ class FriendRequestProtocolTests : XCTestCase {
let masterThread = createContactThread(for: master)
let slaveThread = createContactThread(for: slave)
let expectedStates: [LKFriendRequestStatus : FriendRequestProtocol.FriendRequestUIState] = [
let expectedStates: [LKFriendRequestStatus : FriendRequestProtocol.FriendRequestUIStatus] = [
.none: .none,
.requestExpired: .none,
.requestSending: .none,