|
|
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
//
|
|
|
|
// stringlint:disable
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
|
|
public enum MessageReceiverError: Error, CustomStringConvertible {
|
|
|
|
case duplicateMessage
|
|
|
|
case duplicateMessageNewSnode
|
|
|
|
case duplicateControlMessage
|
|
|
|
case invalidMessage
|
|
|
|
case invalidSender
|
|
|
|
case unknownMessage(SNProtoContent?)
|
|
|
|
case unknownEnvelopeType
|
|
|
|
case noUserX25519KeyPair
|
|
|
|
case noUserED25519KeyPair
|
|
|
|
case invalidSignature
|
|
|
|
case noData
|
|
|
|
case senderBlocked
|
|
|
|
case noThread
|
|
|
|
case selfSend
|
|
|
|
case decryptionFailed
|
|
|
|
case noGroupKeyPair
|
|
|
|
case invalidConfigMessageHandling
|
|
|
|
case requiredThreadNotInConfig
|
|
|
|
case outdatedMessage
|
|
|
|
case ignorableMessage
|
|
|
|
case duplicatedCall
|
|
|
|
case missingRequiredAdminPrivileges
|
|
|
|
case deprecatedMessage
|
|
|
|
|
|
|
|
public var isRetryable: Bool {
|
|
|
|
switch self {
|
|
|
|
case .duplicateMessage, .duplicateMessageNewSnode, .duplicateControlMessage,
|
|
|
|
.invalidMessage, .unknownMessage, .unknownEnvelopeType, .invalidSignature,
|
|
|
|
.noData, .senderBlocked, .noThread, .selfSend, .decryptionFailed,
|
|
|
|
.invalidConfigMessageHandling, .requiredThreadNotInConfig,
|
|
|
|
.outdatedMessage, .ignorableMessage, .missingRequiredAdminPrivileges:
|
|
|
|
return false
|
|
|
|
|
|
|
|
default: return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public var shouldUpdateLastHash: Bool {
|
|
|
|
switch self {
|
|
|
|
// If we get one of these errors then we still want to update the last hash to prevent
|
|
|
|
// retrieving and attempting to process the same messages again (as well as ensure the
|
|
|
|
// next poll doesn't retrieve the same message - these errors are essentially considered
|
|
|
|
// "already successfully processed")
|
|
|
|
case .selfSend, .duplicateControlMessage, .outdatedMessage, .missingRequiredAdminPrivileges:
|
|
|
|
return true
|
|
|
|
|
|
|
|
default: return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public var description: String {
|
|
|
|
switch self {
|
|
|
|
case .duplicateMessage: return "Duplicate message."
|
|
|
|
case .duplicateMessageNewSnode: return "Duplicate message from different service node."
|
|
|
|
case .duplicateControlMessage: return "Duplicate control message."
|
|
|
|
case .invalidMessage: return "Invalid message."
|
|
|
|
case .invalidSender: return "Invalid sender."
|
|
|
|
case .unknownMessage(let content):
|
|
|
|
switch content {
|
|
|
|
case .none: return "Unknown message type (no content)."
|
|
|
|
case .some(let content):
|
|
|
|
let protoInfo: [(String, Bool)] = [
|
|
|
|
("hasDataMessage", (content.dataMessage != nil)),
|
|
|
|
("hasProfile", (content.dataMessage?.profile != nil)),
|
|
|
|
("hasBody", (content.dataMessage?.hasBody == true)),
|
|
|
|
("hasAttachments", (content.dataMessage?.attachments.isEmpty == false)),
|
|
|
|
("hasReaction", (content.dataMessage?.reaction != nil)),
|
|
|
|
("hasQuote", (content.dataMessage?.quote != nil)),
|
|
|
|
("hasLinkPreview", (content.dataMessage?.preview != nil)),
|
|
|
|
("hasOpenGroupInvitation", (content.dataMessage?.openGroupInvitation != nil)),
|
|
|
|
("hasLegacyGroupControlMessage", (content.dataMessage?.closedGroupControlMessage != nil)),
|
|
|
|
("hasGroupV2ControlMessage", (content.dataMessage?.groupUpdateMessage != nil)),
|
|
|
|
("hasTimestamp", (content.dataMessage?.hasTimestamp == true)),
|
|
|
|
("hasSyncTarget", (content.dataMessage?.hasSyncTarget == true)),
|
|
|
|
("hasBlocksCommunityMessageRequests", (content.dataMessage?.hasBlocksCommunityMessageRequests == true)),
|
|
|
|
("hasCallMessage", (content.callMessage != nil)),
|
|
|
|
("hasReceiptMessage", (content.receiptMessage != nil)),
|
|
|
|
("hasTypingMessage", (content.typingMessage != nil)),
|
|
|
|
("hasDataExtractionMessage", (content.dataExtractionNotification != nil)),
|
|
|
|
("hasUnsendRequest", (content.unsendRequest != nil)),
|
|
|
|
("hasMessageRequestResponse", (content.messageRequestResponse != nil)),
|
|
|
|
("hasExpirationTimer", (content.hasExpirationTimer == true)),
|
|
|
|
("hasExpirationType", (content.hasExpirationType == true)),
|
|
|
|
("hasSigTimestamp", (content.hasSigTimestamp == true))
|
|
|
|
]
|
|
|
|
|
|
|
|
let protoInfoString: String = protoInfo
|
|
|
|
.filter { _, val in val }
|
|
|
|
.map { name, _ in name }
|
|
|
|
.joined(separator: ", ")
|
|
|
|
return "Unknown message type (\(protoInfoString))."
|
|
|
|
}
|
|
|
|
|
|
|
|
case .unknownEnvelopeType: return "Unknown envelope type."
|
|
|
|
case .noUserX25519KeyPair: return "Couldn't find user X25519 key pair."
|
|
|
|
case .noUserED25519KeyPair: return "Couldn't find user ED25519 key pair."
|
|
|
|
case .invalidSignature: return "Invalid message signature."
|
|
|
|
case .noData: return "Received an empty envelope."
|
|
|
|
case .senderBlocked: return "Received a message from a blocked user."
|
|
|
|
case .noThread: return "Couldn't find thread for message."
|
|
|
|
case .selfSend: return "Message addressed at self."
|
|
|
|
case .decryptionFailed: return "Decryption failed."
|
|
|
|
|
|
|
|
// Shared sender keys
|
|
|
|
case .noGroupKeyPair: return "Missing group key pair."
|
|
|
|
|
|
|
|
case .invalidConfigMessageHandling: return "Invalid handling of a config message."
|
|
|
|
case .requiredThreadNotInConfig: return "Required thread not in config."
|
|
|
|
case .outdatedMessage: return "Message was sent before a config change which would have removed the message."
|
|
|
|
case .ignorableMessage: return "Message should be ignored."
|
|
|
|
case .duplicatedCall: return "Duplicate call."
|
|
|
|
case .missingRequiredAdminPrivileges: return "Handling this message requires admin privileges which the current user does not have."
|
|
|
|
case .deprecatedMessage: return "This message type has been deprecated."
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|