diff --git a/SessionMessagingKit/Messages/Control Messages/ClosedGroupControlMessage.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupControlMessage.swift index a7170a24f..e54282991 100644 --- a/SessionMessagingKit/Messages/Control Messages/ClosedGroupControlMessage.swift +++ b/SessionMessagingKit/Messages/Control Messages/ClosedGroupControlMessage.swift @@ -250,14 +250,6 @@ public final class ClosedGroupControlMessage : ControlMessage { dataMessageProto.setClosedGroupControlMessage(try closedGroupControlMessage.build()) // Group context try setGroupContextIfNeeded(on: dataMessageProto, using: transaction) - // Expiration timer - // TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation - // if it receives a message without the current expiration timer value attached to it... - var expiration: UInt32 = 0 - if let disappearingMessagesConfiguration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction) { - expiration = disappearingMessagesConfiguration.isEnabled ? disappearingMessagesConfiguration.durationSeconds : 0 - } - dataMessageProto.setExpireTimer(expiration) contentProto.setDataMessage(try dataMessageProto.build()) return try contentProto.build() } catch { diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift index ef56aa52c..e27b50f92 100644 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift +++ b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift @@ -101,15 +101,17 @@ extension ConfigurationMessage { public let encryptionKeyPair: ECKeyPair public let members: Set public let admins: Set + public let expirationTimer: UInt32 public var isValid: Bool { !members.isEmpty && !admins.isEmpty } - public init(publicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: Set, admins: Set) { + public init(publicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: Set, admins: Set, expirationTimer: UInt32) { self.publicKey = publicKey self.name = name self.encryptionKeyPair = encryptionKeyPair self.members = members self.admins = admins + self.expirationTimer = expirationTimer } public required init?(coder: NSCoder) { @@ -118,11 +120,13 @@ extension ConfigurationMessage { let encryptionKeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as! ECKeyPair?, let members = coder.decodeObject(forKey: "members") as! Set?, let admins = coder.decodeObject(forKey: "admins") as! Set? else { return nil } + let expirationTimer = coder.decodeObject(forKey: "expirationTimer") as? UInt32 ?? 0 self.publicKey = publicKey self.name = name self.encryptionKeyPair = encryptionKeyPair self.members = members self.admins = admins + self.expirationTimer = expirationTimer } public func encode(with coder: NSCoder) { @@ -131,6 +135,7 @@ extension ConfigurationMessage { coder.encode(encryptionKeyPair, forKey: "encryptionKeyPair") coder.encode(members, forKey: "members") coder.encode(admins, forKey: "admins") + coder.encode(expirationTimer, forKey: "expirationTimer") } public static func fromProto(_ proto: SNProtoConfigurationMessageClosedGroup) -> ClosedGroup? { @@ -146,7 +151,8 @@ extension ConfigurationMessage { } let members = Set(proto.members.map { $0.toHexString() }) let admins = Set(proto.admins.map { $0.toHexString() }) - let result = ClosedGroup(publicKey: publicKey, name: name, encryptionKeyPair: encryptionKeyPair, members: members, admins: admins) + let expirationTimer = proto.expirationTimer + let result = ClosedGroup(publicKey: publicKey, name: name, encryptionKeyPair: encryptionKeyPair, members: members, admins: admins, expirationTimer: expirationTimer) guard result.isValid else { return nil } return result } @@ -165,6 +171,7 @@ extension ConfigurationMessage { } result.setMembers(members.map { Data(hex: $0) }) result.setAdmins(admins.map { Data(hex: $0) }) + result.setExpirationTimer(expirationTimer) do { return try result.build() } catch { diff --git a/SessionMessagingKit/Protos/Generated/SNProto.swift b/SessionMessagingKit/Protos/Generated/SNProto.swift index 84cfdbd75..997eab59c 100644 --- a/SessionMessagingKit/Protos/Generated/SNProto.swift +++ b/SessionMessagingKit/Protos/Generated/SNProto.swift @@ -2100,6 +2100,9 @@ extension SNProtoDataMessage.SNProtoDataMessageBuilder { } builder.setMembers(members) builder.setAdmins(admins) + if hasExpirationTimer { + builder.setExpirationTimer(expirationTimer) + } return builder } @@ -2141,6 +2144,10 @@ extension SNProtoDataMessage.SNProtoDataMessageBuilder { proto.admins = wrappedItems } + @objc public func setExpirationTimer(_ valueParam: UInt32) { + proto.expirationTimer = valueParam + } + @objc public func build() throws -> SNProtoConfigurationMessageClosedGroup { return try SNProtoConfigurationMessageClosedGroup.parseProto(proto) } @@ -2182,6 +2189,13 @@ extension SNProtoDataMessage.SNProtoDataMessageBuilder { return proto.admins } + @objc public var expirationTimer: UInt32 { + return proto.expirationTimer + } + @objc public var hasExpirationTimer: Bool { + return proto.hasExpirationTimer + } + private init(proto: SessionProtos_ConfigurationMessage.ClosedGroup, encryptionKeyPair: SNProtoKeyPair?) { self.proto = proto diff --git a/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift b/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift index c64270451..37c95f8f0 100644 --- a/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift +++ b/SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift @@ -971,6 +971,15 @@ struct SessionProtos_ConfigurationMessage { var admins: [Data] = [] + var expirationTimer: UInt32 { + get {return _expirationTimer ?? 0} + set {_expirationTimer = newValue} + } + /// Returns true if `expirationTimer` has been explicitly set. + var hasExpirationTimer: Bool {return self._expirationTimer != nil} + /// Clears the value of `expirationTimer`. Subsequent reads from it will return its default value. + mutating func clearExpirationTimer() {self._expirationTimer = nil} + var unknownFields = SwiftProtobuf.UnknownStorage() init() {} @@ -978,6 +987,7 @@ struct SessionProtos_ConfigurationMessage { fileprivate var _publicKey: Data? = nil fileprivate var _name: String? = nil fileprivate var _encryptionKeyPair: SessionProtos_KeyPair? = nil + fileprivate var _expirationTimer: UInt32? = nil } struct Contact { @@ -2294,6 +2304,7 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message, 3: .same(proto: "encryptionKeyPair"), 4: .same(proto: "members"), 5: .same(proto: "admins"), + 6: .same(proto: "expirationTimer"), ] public var isInitialized: Bool { @@ -2312,6 +2323,7 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message, case 3: try { try decoder.decodeSingularMessageField(value: &self._encryptionKeyPair) }() case 4: try { try decoder.decodeRepeatedBytesField(value: &self.members) }() case 5: try { try decoder.decodeRepeatedBytesField(value: &self.admins) }() + case 6: try { try decoder.decodeSingularUInt32Field(value: &self._expirationTimer) }() default: break } } @@ -2333,6 +2345,9 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message, if !self.admins.isEmpty { try visitor.visitRepeatedBytesField(value: self.admins, fieldNumber: 5) } + if let v = self._expirationTimer { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 6) + } try unknownFields.traverse(visitor: &visitor) } @@ -2342,6 +2357,7 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message, if lhs._encryptionKeyPair != rhs._encryptionKeyPair {return false} if lhs.members != rhs.members {return false} if lhs.admins != rhs.admins {return false} + if lhs._expirationTimer != rhs._expirationTimer {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/SessionMessagingKit/Protos/SessionProtos.proto b/SessionMessagingKit/Protos/SessionProtos.proto index 5650d9586..7d9d5f56e 100644 --- a/SessionMessagingKit/Protos/SessionProtos.proto +++ b/SessionMessagingKit/Protos/SessionProtos.proto @@ -161,6 +161,7 @@ message ConfigurationMessage { optional KeyPair encryptionKeyPair = 3; repeated bytes members = 4; repeated bytes admins = 5; + optional uint32 expirationTimer = 6; } message Contact { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 4752de9b5..c2b65a49b 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -207,8 +207,7 @@ extension MessageReceiver { let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys() for closedGroup in message.closedGroups { guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue } - handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, - members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: 0, messageSentTimestamp: message.sentTimestamp!, using: transaction) + handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: closedGroup.expirationTimer, messageSentTimestamp: message.sentTimestamp!, using: transaction) } // Open groups for openGroupURL in message.openGroups { diff --git a/SignalUtilitiesKit/Messaging/ConfigurationMessage+Convenience.swift b/SignalUtilitiesKit/Messaging/ConfigurationMessage+Convenience.swift index 7458aa463..618db9117 100644 --- a/SignalUtilitiesKit/Messaging/ConfigurationMessage+Convenience.swift +++ b/SignalUtilitiesKit/Messaging/ConfigurationMessage+Convenience.swift @@ -22,7 +22,7 @@ extension ConfigurationMessage { 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)) + members: Set(thread.groupModel.groupMemberIds), admins: Set(thread.groupModel.groupAdminIds), expirationTimer: thread.disappearingMessagesDuration(with: transaction)) closedGroups.insert(closedGroup) case .openGroup: if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) {