Merge pull request #431 from Brice-W/exp-timer-config-message

Add Closed Group Expiration Timer Setting to Configuration Message
This commit is contained in:
Niels Andriesse 2021-07-07 15:07:40 +10:00 committed by GitHub
commit 4a0a66533d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 42 additions and 13 deletions

View file

@ -250,14 +250,6 @@ public final class ClosedGroupControlMessage : ControlMessage {
dataMessageProto.setClosedGroupControlMessage(try closedGroupControlMessage.build()) dataMessageProto.setClosedGroupControlMessage(try closedGroupControlMessage.build())
// Group context // Group context
try setGroupContextIfNeeded(on: dataMessageProto, using: transaction) 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()) contentProto.setDataMessage(try dataMessageProto.build())
return try contentProto.build() return try contentProto.build()
} catch { } catch {

View file

@ -101,15 +101,17 @@ extension ConfigurationMessage {
public let encryptionKeyPair: ECKeyPair public let encryptionKeyPair: ECKeyPair
public let members: Set<String> public let members: Set<String>
public let admins: Set<String> public let admins: Set<String>
public let expirationTimer: UInt32
public var isValid: Bool { !members.isEmpty && !admins.isEmpty } public var isValid: Bool { !members.isEmpty && !admins.isEmpty }
public init(publicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: Set<String>, admins: Set<String>) { public init(publicKey: String, name: String, encryptionKeyPair: ECKeyPair, members: Set<String>, admins: Set<String>, expirationTimer: UInt32) {
self.publicKey = publicKey self.publicKey = publicKey
self.name = name self.name = name
self.encryptionKeyPair = encryptionKeyPair self.encryptionKeyPair = encryptionKeyPair
self.members = members self.members = members
self.admins = admins self.admins = admins
self.expirationTimer = expirationTimer
} }
public required init?(coder: NSCoder) { public required init?(coder: NSCoder) {
@ -118,11 +120,13 @@ extension ConfigurationMessage {
let encryptionKeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as! ECKeyPair?, let encryptionKeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as! ECKeyPair?,
let members = coder.decodeObject(forKey: "members") as! Set<String>?, let members = coder.decodeObject(forKey: "members") as! Set<String>?,
let admins = coder.decodeObject(forKey: "admins") as! Set<String>? else { return nil } let admins = coder.decodeObject(forKey: "admins") as! Set<String>? else { return nil }
let expirationTimer = coder.decodeObject(forKey: "expirationTimer") as? UInt32 ?? 0
self.publicKey = publicKey self.publicKey = publicKey
self.name = name self.name = name
self.encryptionKeyPair = encryptionKeyPair self.encryptionKeyPair = encryptionKeyPair
self.members = members self.members = members
self.admins = admins self.admins = admins
self.expirationTimer = expirationTimer
} }
public func encode(with coder: NSCoder) { public func encode(with coder: NSCoder) {
@ -131,6 +135,7 @@ extension ConfigurationMessage {
coder.encode(encryptionKeyPair, forKey: "encryptionKeyPair") coder.encode(encryptionKeyPair, forKey: "encryptionKeyPair")
coder.encode(members, forKey: "members") coder.encode(members, forKey: "members")
coder.encode(admins, forKey: "admins") coder.encode(admins, forKey: "admins")
coder.encode(expirationTimer, forKey: "expirationTimer")
} }
public static func fromProto(_ proto: SNProtoConfigurationMessageClosedGroup) -> ClosedGroup? { public static func fromProto(_ proto: SNProtoConfigurationMessageClosedGroup) -> ClosedGroup? {
@ -146,7 +151,8 @@ extension ConfigurationMessage {
} }
let members = Set(proto.members.map { $0.toHexString() }) let members = Set(proto.members.map { $0.toHexString() })
let admins = Set(proto.admins.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 } guard result.isValid else { return nil }
return result return result
} }
@ -165,6 +171,7 @@ extension ConfigurationMessage {
} }
result.setMembers(members.map { Data(hex: $0) }) result.setMembers(members.map { Data(hex: $0) })
result.setAdmins(admins.map { Data(hex: $0) }) result.setAdmins(admins.map { Data(hex: $0) })
result.setExpirationTimer(expirationTimer)
do { do {
return try result.build() return try result.build()
} catch { } catch {

View file

@ -2100,6 +2100,9 @@ extension SNProtoDataMessage.SNProtoDataMessageBuilder {
} }
builder.setMembers(members) builder.setMembers(members)
builder.setAdmins(admins) builder.setAdmins(admins)
if hasExpirationTimer {
builder.setExpirationTimer(expirationTimer)
}
return builder return builder
} }
@ -2141,6 +2144,10 @@ extension SNProtoDataMessage.SNProtoDataMessageBuilder {
proto.admins = wrappedItems proto.admins = wrappedItems
} }
@objc public func setExpirationTimer(_ valueParam: UInt32) {
proto.expirationTimer = valueParam
}
@objc public func build() throws -> SNProtoConfigurationMessageClosedGroup { @objc public func build() throws -> SNProtoConfigurationMessageClosedGroup {
return try SNProtoConfigurationMessageClosedGroup.parseProto(proto) return try SNProtoConfigurationMessageClosedGroup.parseProto(proto)
} }
@ -2182,6 +2189,13 @@ extension SNProtoDataMessage.SNProtoDataMessageBuilder {
return proto.admins 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, private init(proto: SessionProtos_ConfigurationMessage.ClosedGroup,
encryptionKeyPair: SNProtoKeyPair?) { encryptionKeyPair: SNProtoKeyPair?) {
self.proto = proto self.proto = proto

View file

@ -971,6 +971,15 @@ struct SessionProtos_ConfigurationMessage {
var admins: [Data] = [] 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() var unknownFields = SwiftProtobuf.UnknownStorage()
init() {} init() {}
@ -978,6 +987,7 @@ struct SessionProtos_ConfigurationMessage {
fileprivate var _publicKey: Data? = nil fileprivate var _publicKey: Data? = nil
fileprivate var _name: String? = nil fileprivate var _name: String? = nil
fileprivate var _encryptionKeyPair: SessionProtos_KeyPair? = nil fileprivate var _encryptionKeyPair: SessionProtos_KeyPair? = nil
fileprivate var _expirationTimer: UInt32? = nil
} }
struct Contact { struct Contact {
@ -2294,6 +2304,7 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message,
3: .same(proto: "encryptionKeyPair"), 3: .same(proto: "encryptionKeyPair"),
4: .same(proto: "members"), 4: .same(proto: "members"),
5: .same(proto: "admins"), 5: .same(proto: "admins"),
6: .same(proto: "expirationTimer"),
] ]
public var isInitialized: Bool { public var isInitialized: Bool {
@ -2312,6 +2323,7 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message,
case 3: try { try decoder.decodeSingularMessageField(value: &self._encryptionKeyPair) }() case 3: try { try decoder.decodeSingularMessageField(value: &self._encryptionKeyPair) }()
case 4: try { try decoder.decodeRepeatedBytesField(value: &self.members) }() case 4: try { try decoder.decodeRepeatedBytesField(value: &self.members) }()
case 5: try { try decoder.decodeRepeatedBytesField(value: &self.admins) }() case 5: try { try decoder.decodeRepeatedBytesField(value: &self.admins) }()
case 6: try { try decoder.decodeSingularUInt32Field(value: &self._expirationTimer) }()
default: break default: break
} }
} }
@ -2333,6 +2345,9 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message,
if !self.admins.isEmpty { if !self.admins.isEmpty {
try visitor.visitRepeatedBytesField(value: self.admins, fieldNumber: 5) 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) try unknownFields.traverse(visitor: &visitor)
} }
@ -2342,6 +2357,7 @@ extension SessionProtos_ConfigurationMessage.ClosedGroup: SwiftProtobuf.Message,
if lhs._encryptionKeyPair != rhs._encryptionKeyPair {return false} if lhs._encryptionKeyPair != rhs._encryptionKeyPair {return false}
if lhs.members != rhs.members {return false} if lhs.members != rhs.members {return false}
if lhs.admins != rhs.admins {return false} if lhs.admins != rhs.admins {return false}
if lhs._expirationTimer != rhs._expirationTimer {return false}
if lhs.unknownFields != rhs.unknownFields {return false} if lhs.unknownFields != rhs.unknownFields {return false}
return true return true
} }

View file

@ -161,6 +161,7 @@ message ConfigurationMessage {
optional KeyPair encryptionKeyPair = 3; optional KeyPair encryptionKeyPair = 3;
repeated bytes members = 4; repeated bytes members = 4;
repeated bytes admins = 5; repeated bytes admins = 5;
optional uint32 expirationTimer = 6;
} }
message Contact { message Contact {

View file

@ -207,8 +207,7 @@ extension MessageReceiver {
let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys() let allClosedGroupPublicKeys = storage.getUserClosedGroupPublicKeys()
for closedGroup in message.closedGroups { for closedGroup in message.closedGroups {
guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue } guard !allClosedGroupPublicKeys.contains(closedGroup.publicKey) else { continue }
handleNewClosedGroup(groupPublicKey: closedGroup.publicKey, name: closedGroup.name, encryptionKeyPair: closedGroup.encryptionKeyPair, 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)
members: [String](closedGroup.members), admins: [String](closedGroup.admins), expirationTimer: 0, messageSentTimestamp: message.sentTimestamp!, using: transaction)
} }
// Open groups // Open groups
for openGroupURL in message.openGroups { for openGroupURL in message.openGroups {

View file

@ -22,7 +22,7 @@ extension ConfigurationMessage {
guard storage.isClosedGroup(groupPublicKey), guard storage.isClosedGroup(groupPublicKey),
let encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey) else { return } let encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(for: groupPublicKey) else { return }
let closedGroup = ClosedGroup(publicKey: groupPublicKey, name: thread.groupModel.groupName!, encryptionKeyPair: encryptionKeyPair, 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) closedGroups.insert(closedGroup)
case .openGroup: case .openGroup:
if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) { if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) {