[WIP] Updated to the latest libSession and started plugging in
Updated the updated group messages encryption/decryption logic to work with the latest libSession Disabled manual PN triggering for updated group messages
This commit is contained in:
parent
4f10277a48
commit
a48327f6f6
|
@ -1 +1 @@
|
|||
Subproject commit e21302b598b5dde44fd72566d8b89d4d41cbb9ce
|
||||
Subproject commit 916a47fcd347332256b744457362639c405aebef
|
|
@ -21,6 +21,9 @@ public extension Message {
|
|||
public var defaultNamespace: SnodeAPI.Namespace? {
|
||||
switch self {
|
||||
case .contact: return .`default`
|
||||
case .closedGroup(let key) where SessionId.Prefix(from: key) == .group:
|
||||
return .groupMessages
|
||||
|
||||
case .closedGroup: return .legacyClosedGroup
|
||||
default: return nil
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public enum MessageReceiver {
|
|||
)
|
||||
|
||||
case (_, .community(let openGroupId, let messageSender, let timestamp, let messageServerId)):
|
||||
plaintext = data
|
||||
plaintext = data.removePadding() // Remove the padding
|
||||
sender = messageSender
|
||||
sentTimestamp = UInt64(floor(timestamp * 1000)) // Convert to ms for database consistency
|
||||
openGroupServerMessageId = UInt64(messageServerId)
|
||||
|
@ -62,6 +62,7 @@ public enum MessageReceiver {
|
|||
using: dependencies
|
||||
)
|
||||
|
||||
plaintext = plaintext.removePadding() // Remove the padding
|
||||
sentTimestamp = UInt64(floor(timestamp * 1000)) // Convert to ms for database consistency
|
||||
openGroupServerMessageId = UInt64(messageServerId)
|
||||
threadVariant = .contact
|
||||
|
@ -85,6 +86,7 @@ public enum MessageReceiver {
|
|||
ciphertext: ciphertext,
|
||||
using: userX25519KeyPair
|
||||
)
|
||||
plaintext = plaintext.removePadding() // Remove the padding
|
||||
sentTimestamp = envelope.timestamp
|
||||
openGroupServerMessageId = nil
|
||||
threadVariant = .contact
|
||||
|
@ -105,13 +107,16 @@ public enum MessageReceiver {
|
|||
)
|
||||
|
||||
guard
|
||||
let envelope: SNProtoEnvelope = try? MessageWrapper.unwrap(data: plaintextEnvelope),
|
||||
let envelope: SNProtoEnvelope = try? MessageWrapper.unwrap(
|
||||
data: plaintextEnvelope,
|
||||
includesWebSocketMessage: false
|
||||
),
|
||||
let envelopeContent: Data = envelope.content
|
||||
else {
|
||||
SNLog("Failed to unwrap data for message from 'default' namespace.")
|
||||
throw MessageReceiverError.invalidMessage
|
||||
}
|
||||
plaintext = envelopeContent
|
||||
plaintext = envelopeContent // Padding already removed for updated groups
|
||||
sentTimestamp = envelope.timestamp
|
||||
openGroupServerMessageId = nil
|
||||
threadVariant = .group
|
||||
|
@ -158,6 +163,7 @@ public enum MessageReceiver {
|
|||
}
|
||||
|
||||
(plaintext, sender) = try decrypt(keyPairs: encryptionKeyPairs)
|
||||
plaintext = plaintext.removePadding() // Remove the padding
|
||||
sentTimestamp = envelope.timestamp
|
||||
openGroupServerMessageId = nil
|
||||
threadVariant = .legacyGroup
|
||||
|
@ -175,7 +181,7 @@ public enum MessageReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
let proto: SNProtoContent = try Result(SNProtoContent.parseData(plaintext.removePadding()))
|
||||
let proto: SNProtoContent = try Result(SNProtoContent.parseData(plaintext))
|
||||
.onFailure { SNLog("Couldn't parse proto due to error: \($0).") }
|
||||
.successOrThrow()
|
||||
let message: Message = try Message.createMessageFrom(proto, sender: sender)
|
||||
|
|
|
@ -179,11 +179,6 @@ public final class MessageSender {
|
|||
.successOrThrow()
|
||||
.base64EncodedString()
|
||||
|
||||
// Config messages should be sent directly rather than via this method
|
||||
case (.contact, _): throw MessageSenderError.invalidConfigMessageHandling
|
||||
case (.closedGroup(let groupPublicKey), _) where SessionId.Prefix(from: groupPublicKey) == .group:
|
||||
throw MessageSenderError.invalidConfigMessageHandling
|
||||
|
||||
// Updated group messages should be wrapped _before_ encrypting
|
||||
case (.closedGroup(let groupPublicKey), .groupMessages) where SessionId.Prefix(from: groupPublicKey) == .group:
|
||||
return try SessionUtil
|
||||
|
@ -204,6 +199,11 @@ public final class MessageSender {
|
|||
)
|
||||
.base64EncodedString()
|
||||
|
||||
// Config messages should be sent directly rather than via this method
|
||||
case (.contact, _): throw MessageSenderError.invalidConfigMessageHandling
|
||||
case (.closedGroup(let groupPublicKey), _) where SessionId.Prefix(from: groupPublicKey) == .group:
|
||||
throw MessageSenderError.invalidConfigMessageHandling
|
||||
|
||||
// Legacy groups used a `05` prefix
|
||||
case (.closedGroup(let groupPublicKey), _):
|
||||
guard let encryptionKeyPair: ClosedGroupKeyPair = try? ClosedGroupKeyPair.fetchLatestKeyPair(db, threadId: groupPublicKey) else {
|
||||
|
@ -262,6 +262,13 @@ public final class MessageSender {
|
|||
details: NotifyPushServerJob.Details(message: snodeMessage)
|
||||
)
|
||||
let shouldNotify: Bool = {
|
||||
// New groups only run via the updated push server so don't notify
|
||||
switch destination {
|
||||
case .closedGroup(let key) where SessionId.Prefix(from: key) == .group:
|
||||
return false
|
||||
default: break
|
||||
}
|
||||
|
||||
switch updatedMessage {
|
||||
case is VisibleMessage, is UnsendRequest: return !isSyncMessage
|
||||
case let callMessage as CallMessage:
|
||||
|
|
|
@ -327,23 +327,31 @@ internal extension SessionUtil {
|
|||
guard case .groupKeys(let conf, _, _) = config else { throw SessionUtilError.invalidConfigObject }
|
||||
|
||||
var ciphertext: [UInt8] = Array(ciphertext)
|
||||
var cSessionId: [CChar] = [CChar](repeating: 0, count: 67)
|
||||
var maybePlaintext: UnsafeMutablePointer<UInt8>? = nil
|
||||
var plaintextLen: Int = 0
|
||||
groups_keys_decrypt_message(
|
||||
let didDecrypt: Bool = groups_keys_decrypt_message(
|
||||
conf,
|
||||
&ciphertext,
|
||||
ciphertext.count,
|
||||
&cSessionId,
|
||||
&maybePlaintext,
|
||||
&plaintextLen
|
||||
)
|
||||
|
||||
// If we got a reported failure then just stop here
|
||||
guard didDecrypt else { throw MessageReceiverError.decryptionFailed }
|
||||
|
||||
// We need to manually free 'maybePlaintext' upon a successful decryption
|
||||
defer { maybePlaintext?.deallocate() }
|
||||
|
||||
guard
|
||||
plaintextLen > 0,
|
||||
let plaintext: Data = maybePlaintext
|
||||
.map({ Data(bytes: $0, count: plaintextLen) })
|
||||
else { throw MessageReceiverError.decryptionFailed }
|
||||
|
||||
return (plaintext, "")
|
||||
return (plaintext, String(cString: cSessionId))
|
||||
} ?? { throw MessageReceiverError.decryptionFailed }()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,11 +80,18 @@ public enum MessageWrapper {
|
|||
}
|
||||
|
||||
/// - Note: `data` shouldn't be base 64 encoded.
|
||||
public static func unwrap(data: Data) throws -> SNProtoEnvelope {
|
||||
public static func unwrap(
|
||||
data: Data,
|
||||
includesWebSocketMessage: Bool = true
|
||||
) throws -> SNProtoEnvelope {
|
||||
do {
|
||||
let webSocketMessage = try WebSocketProtoWebSocketMessage.parseData(data)
|
||||
let envelope = webSocketMessage.request!.body!
|
||||
return try SNProtoEnvelope.parseData(envelope)
|
||||
let envelopeData: Data = try {
|
||||
guard includesWebSocketMessage else { return data }
|
||||
|
||||
let webSocketMessage = try WebSocketProtoWebSocketMessage.parseData(data)
|
||||
return webSocketMessage.request!.body!
|
||||
}()
|
||||
return try SNProtoEnvelope.parseData(envelopeData)
|
||||
} catch let error {
|
||||
SNLog("Failed to unwrap data: \(error).")
|
||||
throw Error.failedToUnwrapData
|
||||
|
|
|
@ -1805,6 +1805,20 @@ fileprivate extension LibSessionSpec {
|
|||
// MARK: - GROUP_INFO
|
||||
|
||||
fileprivate extension LibSessionSpec {
|
||||
/// This function can be used to regenerate the hard-coded `keysDump` value if needed due to `libSession` changes
|
||||
/// resulting in the dump changing
|
||||
private static func generateKeysDump(for keysConf: UnsafeMutablePointer<config_group_keys>?) throws -> String {
|
||||
var dumpResult: UnsafeMutablePointer<UInt8>? = nil
|
||||
var dumpResultLen: Int = 0
|
||||
try CExceptionHelper.performSafely {
|
||||
groups_keys_dump(keysConf, &dumpResult, &dumpResultLen)
|
||||
}
|
||||
|
||||
let dumpData: Data = Data(bytes: dumpResult!, count: dumpResultLen)
|
||||
dumpResult?.deallocate()
|
||||
return dumpData.toHexString()
|
||||
}
|
||||
|
||||
class func groupInfoSpec() {
|
||||
context("GROUP_INFO") {
|
||||
// MARK: -- generates config correctly
|
||||
|
@ -1814,8 +1828,24 @@ fileprivate extension LibSessionSpec {
|
|||
hex: "0123456789abcdef0123456789abcdeffedcba9876543210fedcba9876543210"
|
||||
)
|
||||
|
||||
// Since we can't test the group without encryption keys and the C API doesn't have
|
||||
// a way to manually provide encryption keys we needed to create a dump with valid
|
||||
// key data and load that in so we can test the other cases, this dump contains a
|
||||
// single admin member and a single encryption key
|
||||
let keysDump: Data = Data(hex: "64363a6163746976656c65343a6b6579736c6565")
|
||||
let cachedKeysDump: (data: UnsafePointer<UInt8>, length: Int)? = keysDump.withUnsafeBytes { unsafeBytes in
|
||||
return unsafeBytes.baseAddress.map {
|
||||
(
|
||||
$0.assumingMemoryBound(to: UInt8.self),
|
||||
unsafeBytes.count
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Would be good to move these into the libSession-util instead of using Sodium separately
|
||||
let identity = try! Identity.generate(from: userSeed)
|
||||
let keyPair: KeyPair = Crypto().generate(.ed25519KeyPair(seed: seed))!
|
||||
var userEdSK: [UInt8] = identity.ed25519KeyPair.secretKey
|
||||
var edPK: [UInt8] = keyPair.publicKey
|
||||
var edSK: [UInt8] = keyPair.secretKey
|
||||
|
||||
|
@ -1828,9 +1858,18 @@ fileprivate extension LibSessionSpec {
|
|||
var conf: UnsafeMutablePointer<config_object>? = nil
|
||||
expect(groups_info_init(&conf, &edPK, &edSK, nil, 0, &error)).to(equal(0))
|
||||
|
||||
var membersConf: UnsafeMutablePointer<config_object>? = nil
|
||||
expect(groups_members_init(&membersConf, &edPK, &edSK, nil, 0, &error)).to(equal(0))
|
||||
|
||||
var keysConf1: UnsafeMutablePointer<config_group_keys>? = nil
|
||||
expect(groups_keys_init(&keysConf1, &userEdSK, &edPK, &edSK, conf, membersConf, cachedKeysDump?.data, (cachedKeysDump?.length ?? 0), &error)).to(equal(0))
|
||||
|
||||
var conf2: UnsafeMutablePointer<config_object>? = nil
|
||||
expect(groups_info_init(&conf2, &edPK, &edSK, nil, 0, &error)).to(equal(0))
|
||||
|
||||
var keysConf2: UnsafeMutablePointer<config_group_keys>? = nil
|
||||
expect(groups_keys_init(&keysConf2, &userEdSK, &edPK, &edSK, conf2, membersConf, cachedKeysDump?.data, (cachedKeysDump?.length ?? 0), &error)).to(equal(0))
|
||||
|
||||
expect(groups_info_set_name(conf, "GROUP Name")).to(equal(0))
|
||||
expect(config_needs_push(conf)).to(beTrue())
|
||||
expect(config_needs_dump(conf)).to(beTrue())
|
||||
|
|
Loading…
Reference in New Issue