2020-11-09 00:58:47 +01:00
|
|
|
import SessionUtilitiesKit
|
2020-11-05 23:17:05 +01:00
|
|
|
|
2020-11-08 02:34:08 +01:00
|
|
|
internal enum MessageReceiver {
|
|
|
|
|
|
|
|
internal enum Error : LocalizedError {
|
2020-11-27 05:13:42 +01:00
|
|
|
case duplicateMessage
|
2020-11-06 06:31:56 +01:00
|
|
|
case invalidMessage
|
2020-11-07 23:00:10 +01:00
|
|
|
case unknownMessage
|
2020-11-09 00:33:26 +01:00
|
|
|
case unknownEnvelopeType
|
|
|
|
case noUserPublicKey
|
|
|
|
case noData
|
2020-11-17 06:23:13 +01:00
|
|
|
case senderBlocked
|
2020-11-18 05:53:45 +01:00
|
|
|
case noThread
|
2020-11-23 05:58:48 +01:00
|
|
|
case selfSend
|
2020-11-06 09:32:09 +01:00
|
|
|
// Shared sender keys
|
|
|
|
case invalidGroupPublicKey
|
|
|
|
case noGroupPrivateKey
|
|
|
|
case sharedSecretGenerationFailed
|
2020-11-06 06:31:56 +01:00
|
|
|
|
2020-11-18 05:36:51 +01:00
|
|
|
internal var isRetryable: Bool {
|
|
|
|
switch self {
|
2020-11-27 05:13:42 +01:00
|
|
|
case .duplicateMessage, .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false
|
2020-11-18 05:36:51 +01:00
|
|
|
default: return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-08 02:34:08 +01:00
|
|
|
internal var errorDescription: String? {
|
2020-11-06 06:31:56 +01:00
|
|
|
switch self {
|
2020-11-27 05:13:42 +01:00
|
|
|
case .duplicateMessage: return "Duplicate message."
|
2020-11-06 06:31:56 +01:00
|
|
|
case .invalidMessage: return "Invalid message."
|
2020-11-07 23:00:10 +01:00
|
|
|
case .unknownMessage: return "Unknown message type."
|
2020-11-09 00:33:26 +01:00
|
|
|
case .unknownEnvelopeType: return "Unknown envelope type."
|
|
|
|
case .noUserPublicKey: return "Couldn't find user key pair."
|
|
|
|
case .noData: return "Received an empty envelope."
|
2020-11-17 06:23:13 +01:00
|
|
|
case .senderBlocked: return "Received a message from a blocked user."
|
2020-11-18 05:53:45 +01:00
|
|
|
case .noThread: return "Couldn't find thread for message."
|
2020-11-06 09:32:09 +01:00
|
|
|
// Shared sender keys
|
|
|
|
case .invalidGroupPublicKey: return "Invalid group public key."
|
|
|
|
case .noGroupPrivateKey: return "Missing group private key."
|
|
|
|
case .sharedSecretGenerationFailed: return "Couldn't generate a shared secret."
|
|
|
|
case .selfSend: return "Message addressed at self."
|
2020-11-06 06:31:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-30 01:00:28 +01:00
|
|
|
internal static func parse(_ data: Data, openGroupMessageServerID: UInt64?, using transaction: Any) throws -> (Message, SNProtoContent) {
|
2020-11-23 05:58:48 +01:00
|
|
|
let userPublicKey = Configuration.shared.storage.getUserPublicKey()
|
2020-11-30 04:20:36 +01:00
|
|
|
let isOpenGroupMessage = (openGroupMessageServerID != nil)
|
2020-11-09 00:33:26 +01:00
|
|
|
// Parse the envelope
|
2020-11-17 06:23:13 +01:00
|
|
|
let envelope = try SNProtoEnvelope.parseData(data)
|
2020-11-27 05:13:42 +01:00
|
|
|
let storage = Configuration.shared.storage
|
|
|
|
guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) else { throw Error.duplicateMessage }
|
|
|
|
storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction)
|
2020-11-09 00:33:26 +01:00
|
|
|
// Decrypt the contents
|
|
|
|
let plaintext: Data
|
2020-11-17 06:23:13 +01:00
|
|
|
let sender: String
|
2020-11-18 05:53:45 +01:00
|
|
|
var groupPublicKey: String? = nil
|
2020-11-30 01:00:28 +01:00
|
|
|
if isOpenGroupMessage {
|
|
|
|
(plaintext, sender) = (envelope.content!, envelope.source!)
|
|
|
|
} else {
|
|
|
|
switch envelope.type {
|
|
|
|
case .unidentifiedSender: (plaintext, sender) = try decryptWithSignalProtocol(envelope: envelope, using: transaction)
|
|
|
|
case .closedGroupCiphertext:
|
|
|
|
(plaintext, sender) = try decryptWithSharedSenderKeys(envelope: envelope, using: transaction)
|
|
|
|
groupPublicKey = envelope.source
|
|
|
|
default: throw Error.unknownEnvelopeType
|
|
|
|
}
|
2020-11-09 00:33:26 +01:00
|
|
|
}
|
2020-11-17 06:23:13 +01:00
|
|
|
// Don't process the envelope any further if the sender is blocked
|
2020-11-25 06:15:16 +01:00
|
|
|
guard !isBlocked(sender) else { throw Error.senderBlocked }
|
2020-11-23 05:58:48 +01:00
|
|
|
// Ignore self sends
|
|
|
|
guard sender != userPublicKey else { throw Error.selfSend }
|
2020-11-09 03:56:50 +01:00
|
|
|
// Parse the proto
|
2020-11-06 04:05:45 +01:00
|
|
|
let proto: SNProtoContent
|
|
|
|
do {
|
2020-11-09 00:33:26 +01:00
|
|
|
proto = try SNProtoContent.parseData((plaintext as NSData).removePadding())
|
2020-11-06 04:05:45 +01:00
|
|
|
} catch {
|
|
|
|
SNLog("Couldn't parse proto due to error: \(error).")
|
2020-11-07 23:00:10 +01:00
|
|
|
throw error
|
2020-11-06 04:05:45 +01:00
|
|
|
}
|
2020-11-09 03:56:50 +01:00
|
|
|
// Parse the message
|
2020-11-06 06:31:56 +01:00
|
|
|
let message: Message? = {
|
|
|
|
if let readReceipt = ReadReceipt.fromProto(proto) { return readReceipt }
|
|
|
|
if let typingIndicator = TypingIndicator.fromProto(proto) { return typingIndicator }
|
|
|
|
if let closedGroupUpdate = ClosedGroupUpdate.fromProto(proto) { return closedGroupUpdate }
|
|
|
|
if let expirationTimerUpdate = ExpirationTimerUpdate.fromProto(proto) { return expirationTimerUpdate }
|
|
|
|
if let visibleMessage = VisibleMessage.fromProto(proto) { return visibleMessage }
|
|
|
|
return nil
|
|
|
|
}()
|
|
|
|
if let message = message {
|
2020-11-30 01:00:28 +01:00
|
|
|
if isOpenGroupMessage {
|
|
|
|
guard message is VisibleMessage else { throw Error.invalidMessage }
|
|
|
|
}
|
2020-11-17 06:23:13 +01:00
|
|
|
message.sender = sender
|
2020-11-23 05:58:48 +01:00
|
|
|
message.recipient = userPublicKey
|
2020-11-19 06:28:30 +01:00
|
|
|
message.sentTimestamp = envelope.timestamp
|
2020-11-10 05:48:47 +01:00
|
|
|
message.receivedTimestamp = NSDate.millisecondTimestamp()
|
2020-11-18 05:53:45 +01:00
|
|
|
message.groupPublicKey = groupPublicKey
|
2020-11-30 01:00:28 +01:00
|
|
|
message.openGroupServerMessageID = openGroupMessageServerID
|
2020-11-26 23:07:24 +01:00
|
|
|
var isValid = message.isValid
|
|
|
|
if message is VisibleMessage && !isValid && proto.dataMessage?.attachments.isEmpty == false {
|
|
|
|
isValid = true
|
|
|
|
}
|
|
|
|
guard isValid else { throw Error.invalidMessage }
|
2020-11-20 01:10:53 +01:00
|
|
|
return (message, proto)
|
2020-11-06 06:31:56 +01:00
|
|
|
} else {
|
2020-11-07 23:03:08 +01:00
|
|
|
throw Error.unknownMessage
|
2020-11-06 06:31:56 +01:00
|
|
|
}
|
2020-11-06 04:05:45 +01:00
|
|
|
}
|
2020-11-05 23:17:05 +01:00
|
|
|
}
|