mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge branch 'dev' into voice-messages-2
This commit is contained in:
commit
6fbc7396b8
8 changed files with 77 additions and 43 deletions
|
@ -74,6 +74,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
|
||||||
|
|
||||||
- (nullable OWSAES256Key *)profileKeyForRecipientId:(NSString *)recipientId;
|
- (nullable OWSAES256Key *)profileKeyForRecipientId:(NSString *)recipientId;
|
||||||
|
|
||||||
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID avoidWriteTransaction:(BOOL)avoidWriteTransaction;
|
||||||
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID;
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID;
|
||||||
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||||
|
|
||||||
|
|
|
@ -1025,6 +1025,11 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID
|
||||||
|
{
|
||||||
|
return [self profileNameForRecipientWithID:recipientID avoidingWriteTransaction:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID avoidingWriteTransaction:(BOOL)avoidWriteTransaction
|
||||||
{
|
{
|
||||||
if ([self.tsAccountManager.localNumber isEqualToString:recipientID]) {
|
if ([self.tsAccountManager.localNumber isEqualToString:recipientID]) {
|
||||||
return self.localUserProfile.profileName;
|
return self.localUserProfile.profileName;
|
||||||
|
@ -1047,18 +1052,22 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__block NSString *result;
|
if (!avoidWriteTransaction) {
|
||||||
|
__block NSString *result;
|
||||||
|
|
||||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
result = [self profileNameForRecipientWithID:recipientID transaction:transaction];
|
result = [self profileNameForRecipientWithID:recipientID transaction:transaction];
|
||||||
} error:nil];
|
} error:nil];
|
||||||
|
|
||||||
NSString *shortID = [recipientID substringWithRange:NSMakeRange(recipientID.length - 8, 8)];
|
NSString *shortID = [recipientID substringWithRange:NSMakeRange(recipientID.length - 8, 8)];
|
||||||
NSString *suffix = [NSString stringWithFormat:@" (...%@)", shortID];
|
NSString *suffix = [NSString stringWithFormat:@" (...%@)", shortID];
|
||||||
if ([result hasSuffix:suffix]) {
|
if ([result hasSuffix:suffix]) {
|
||||||
return [result substringToIndex:result.length - suffix.length];
|
return [result substringToIndex:result.length - suffix.length];
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return result;
|
return recipientID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,15 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
} else {
|
} else {
|
||||||
// Establish sessions if needed
|
// Establish sessions if needed
|
||||||
establishSessionsIfNeeded(with: [String](members), using: transaction)
|
establishSessionsIfNeeded(with: [String](members), using: transaction)
|
||||||
|
// Send closed group update messages to any new members using established channels
|
||||||
|
for member in newMembers {
|
||||||
|
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
|
||||||
|
thread.save(with: transaction)
|
||||||
|
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name,
|
||||||
|
groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [], members: membersAsData, admins: adminsAsData)
|
||||||
|
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
||||||
|
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
||||||
|
}
|
||||||
// Send out the user's new ratchet to all members (minus the removed ones) using established channels
|
// Send out the user's new ratchet to all members (minus the removed ones) using established channels
|
||||||
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
||||||
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
||||||
|
@ -150,7 +159,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if !newMembers.isEmpty {
|
||||||
seal.fulfill(())
|
seal.fulfill(())
|
||||||
// Generate ratchets for any new members
|
// Generate ratchets for any new members
|
||||||
newSenderKeys = newMembers.map { publicKey in
|
newSenderKeys = newMembers.map { publicKey in
|
||||||
|
@ -162,17 +171,24 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
members: membersAsData, admins: adminsAsData)
|
members: membersAsData, admins: adminsAsData)
|
||||||
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
||||||
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
||||||
}
|
// Establish sessions if needed
|
||||||
// Establish sessions if needed
|
establishSessionsIfNeeded(with: [String](newMembers), using: transaction)
|
||||||
establishSessionsIfNeeded(with: [String](newMembers), using: transaction)
|
// Send closed group update messages to the new members using established channels
|
||||||
// Send closed group update messages to the new members using established channels
|
var allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey)
|
||||||
var allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey)
|
allSenderKeys.formUnion(newSenderKeys)
|
||||||
allSenderKeys.formUnion(newSenderKeys)
|
for member in newMembers {
|
||||||
for member in newMembers {
|
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
|
||||||
let thread = TSContactThread.getOrCreateThread(withContactId: member, transaction: transaction)
|
thread.save(with: transaction)
|
||||||
thread.save(with: transaction)
|
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name,
|
||||||
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.new(groupPublicKey: Data(hex: groupPublicKey), name: name,
|
groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData)
|
||||||
groupPrivateKey: Data(hex: groupPrivateKey), senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData)
|
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
||||||
|
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
seal.fulfill(())
|
||||||
|
let allSenderKeys = Storage.getAllClosedGroupSenderKeys(for: groupPublicKey)
|
||||||
|
let closedGroupUpdateMessageKind = ClosedGroupUpdateMessage.Kind.info(groupPublicKey: Data(hex: groupPublicKey), name: name,
|
||||||
|
senderKeys: [ClosedGroupSenderKey](allSenderKeys), members: membersAsData, admins: adminsAsData)
|
||||||
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
let closedGroupUpdateMessage = ClosedGroupUpdateMessage(thread: thread, kind: closedGroupUpdateMessageKind)
|
||||||
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
messageSenderJobQueue.add(message: closedGroupUpdateMessage, transaction: transaction)
|
||||||
}
|
}
|
||||||
|
@ -265,7 +281,7 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
let missingSenderKeys = Set(members).subtracting(senderKeys.map { $0.publicKey.toHexString() })
|
let missingSenderKeys = Set(members).subtracting(senderKeys.map { $0.publicKey.toHexString() })
|
||||||
let userPublicKey = getUserHexEncodedPublicKey()
|
let userPublicKey = getUserHexEncodedPublicKey()
|
||||||
if missingSenderKeys.contains(userPublicKey) {
|
if missingSenderKeys.contains(userPublicKey) {
|
||||||
establishSessionsIfNeeded(with: [String](missingSenderKeys), using: transaction)
|
establishSessionsIfNeeded(with: [String](members), using: transaction)
|
||||||
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
||||||
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
||||||
for member in members {
|
for member in members {
|
||||||
|
@ -283,9 +299,15 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
// Create the group
|
// Create the group
|
||||||
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
|
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
|
||||||
let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins)
|
let group = TSGroupModel(title: name, memberIds: members, image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins)
|
||||||
let thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction)
|
let thread: TSGroupThread
|
||||||
thread.usesSharedSenderKeys = true
|
if let t = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) {
|
||||||
thread.save(with: transaction)
|
thread = t
|
||||||
|
thread.setGroupModel(group, with: transaction)
|
||||||
|
} else {
|
||||||
|
thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction)
|
||||||
|
thread.usesSharedSenderKeys = true
|
||||||
|
thread.save(with: transaction)
|
||||||
|
}
|
||||||
SSKEnvironment.shared.profileManager.addThread(toProfileWhitelist: thread)
|
SSKEnvironment.shared.profileManager.addThread(toProfileWhitelist: thread)
|
||||||
// Add the group to the user's set of public keys to poll for
|
// Add the group to the user's set of public keys to poll for
|
||||||
Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction)
|
Storage.setClosedGroupPrivateKey(groupPrivateKey.toHexString(), for: groupPublicKey, using: transaction)
|
||||||
|
@ -389,7 +411,9 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
// Respond to the request
|
// Respond to the request
|
||||||
print("[Loki] Responding to sender key request from: \(senderPublicKey).")
|
print("[Loki] Responding to sender key request from: \(senderPublicKey).")
|
||||||
SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) // This internally takes care of multi device
|
SessionManagementProtocol.sendSessionRequestIfNeeded(to: senderPublicKey, using: transaction) // This internally takes care of multi device
|
||||||
let userRatchet = SharedSenderKeysImplementation.shared.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction)
|
guard let userRatchet = Storage.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) else {
|
||||||
|
return print("[Loki] Missing own ratchet.")
|
||||||
|
}
|
||||||
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey))
|
||||||
let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction)
|
let thread = TSContactThread.getOrCreateThread(withContactId: senderPublicKey, transaction: transaction)
|
||||||
thread.save(with: transaction)
|
thread.save(with: transaction)
|
||||||
|
@ -402,23 +426,9 @@ public final class ClosedGroupsProtocol : NSObject {
|
||||||
private static func handleSenderKeyMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
|
private static func handleSenderKeyMessage(_ closedGroupUpdate: SSKProtoDataMessageClosedGroupUpdate, from senderPublicKey: String, using transaction: YapDatabaseReadWriteTransaction) {
|
||||||
// Prepare
|
// Prepare
|
||||||
let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString()
|
let groupPublicKey = closedGroupUpdate.groupPublicKey.toHexString()
|
||||||
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
|
|
||||||
guard let thread = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) else {
|
|
||||||
return print("[Loki] Ignoring closed group sender key for nonexistent group.")
|
|
||||||
}
|
|
||||||
let group = thread.groupModel
|
|
||||||
guard let senderKey = closedGroupUpdate.senderKeys.first else {
|
guard let senderKey = closedGroupUpdate.senderKeys.first else {
|
||||||
return print("[Loki] Ignoring invalid closed group sender key.")
|
return print("[Loki] Ignoring invalid closed group sender key.")
|
||||||
}
|
}
|
||||||
// Check that the requesting user is a member of the group
|
|
||||||
var membersAndLinkedDevices: Set<String> = Set(group.groupMemberIds)
|
|
||||||
for member in group.groupMemberIds {
|
|
||||||
let deviceLinks = OWSPrimaryStorage.shared().getDeviceLinks(for: member, in: transaction)
|
|
||||||
membersAndLinkedDevices.formUnion(deviceLinks.flatMap { [ $0.master.publicKey, $0.slave.publicKey ] })
|
|
||||||
}
|
|
||||||
guard membersAndLinkedDevices.contains(senderPublicKey) else {
|
|
||||||
return print("[Loki] Ignoring closed group sender key from non-member.")
|
|
||||||
}
|
|
||||||
guard senderKey.publicKey.toHexString() == senderPublicKey else {
|
guard senderKey.publicKey.toHexString() == senderPublicKey else {
|
||||||
return print("[Loki] Ignoring invalid closed group sender key.")
|
return print("[Loki] Ignoring invalid closed group sender key.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,7 +177,12 @@ public final class SharedSenderKeysImplementation : NSObject {
|
||||||
throw RatchetingError.messageKeyMissing(targetKeyIndex: keyIndex, groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey)
|
throw RatchetingError.messageKeyMissing(targetKeyIndex: keyIndex, groupPublicKey: groupPublicKey, senderPublicKey: senderPublicKey)
|
||||||
}
|
}
|
||||||
let aes = try AES(key: Data(hex: messageKey).bytes, blockMode: gcm, padding: .noPadding)
|
let aes = try AES(key: Data(hex: messageKey).bytes, blockMode: gcm, padding: .noPadding)
|
||||||
return Data(try aes.decrypt(ciphertext.bytes))
|
do {
|
||||||
|
return Data(try aes.decrypt(ciphertext.bytes))
|
||||||
|
} catch {
|
||||||
|
ClosedGroupsProtocol.requestSenderKey(for: groupPublicKey, senderPublicKey: senderPublicKey, using: transaction)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func isClosedGroup(_ publicKey: String) -> Bool {
|
@objc public func isClosedGroup(_ publicKey: String) -> Bool {
|
||||||
|
|
|
@ -13,6 +13,15 @@ public final class UserDisplayNameUtilities : NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Sessions
|
// MARK: Sessions
|
||||||
|
@objc(getPrivateChatDisplayNameAvoidWriteTransaction:)
|
||||||
|
public static func getPrivateChatDisplayNameAvoidingWriteTransaction(for publicKey: String) -> String? {
|
||||||
|
if publicKey == userPublicKey {
|
||||||
|
return userDisplayName
|
||||||
|
} else {
|
||||||
|
return SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: publicKey, avoidingWriteTransaction: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc public static func getPrivateChatDisplayName(for publicKey: String) -> String? {
|
@objc public static func getPrivateChatDisplayName(for publicKey: String) -> String? {
|
||||||
if publicKey == userPublicKey {
|
if publicKey == userPublicKey {
|
||||||
return userDisplayName
|
return userDisplayName
|
||||||
|
|
|
@ -667,7 +667,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||||
|
|
||||||
BOOL isSyncMessage = [message isKindOfClass:[OWSOutgoingSyncMessage class]];
|
BOOL isSyncMessage = [message isKindOfClass:[OWSOutgoingSyncMessage class]];
|
||||||
if (thread == nil && !isSyncMessage) {
|
if (thread == nil && !isSyncMessage) {
|
||||||
OWSFailDebug(@"Missing thread for non-sync message.");
|
|
||||||
|
|
||||||
// The thread has been deleted since the message was enqueued.
|
// The thread has been deleted since the message was enqueued.
|
||||||
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients,
|
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients,
|
||||||
|
|
|
@ -133,7 +133,7 @@ const int32_t kGroupIdLength = 16;
|
||||||
|
|
||||||
if ([membersWhoLeft count] > 0) {
|
if ([membersWhoLeft count] > 0) {
|
||||||
NSArray *oldMembersNames = [[membersWhoLeft allObjects] map:^NSString*(NSString* item) {
|
NSArray *oldMembersNames = [[membersWhoLeft allObjects] map:^NSString*(NSString* item) {
|
||||||
return [LKUserDisplayNameUtilities getPrivateChatDisplayNameFor:item];
|
return [LKUserDisplayNameUtilities getPrivateChatDisplayNameAvoidWriteTransaction:item];
|
||||||
}];
|
}];
|
||||||
updatedGroupInfoString = [updatedGroupInfoString
|
updatedGroupInfoString = [updatedGroupInfoString
|
||||||
stringByAppendingString:[NSString
|
stringByAppendingString:[NSString
|
||||||
|
|
|
@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
- (OWSAES256Key *)localProfileKey;
|
- (OWSAES256Key *)localProfileKey;
|
||||||
|
|
||||||
- (nullable NSString *)localProfileName;
|
- (nullable NSString *)localProfileName;
|
||||||
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID avoidingWriteTransaction:(BOOL)avoidWriteTransaction;
|
||||||
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID;
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID;
|
||||||
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
- (nullable NSString *)profileNameForRecipientWithID:(NSString *)recipientID transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||||
- (nullable NSString *)profilePictureURL;
|
- (nullable NSString *)profilePictureURL;
|
||||||
|
|
Loading…
Reference in a new issue