mirror of
https://github.com/lux-tel/session-ios.git
synced 2026-10-30 20:38:32 +00:00
• Refactored the MessageViewModel to be a dumb data types instead of a monolithic query • Refactored the ConversationViewModel due to handle the updated MessageViewModel • Refactored OWSAudioPlayer into Swift • Refactored the OpenGroupManager and OpenGroupManagerCache to be a single actor (CommunityManager), it also holds community state in memory • Removed a bunch of GRDB-specific relationship code (just makes things messy since we have raw SQL elsewhere) • Fixed a bug where the ObservationBuilder could incorrectly run queries in cancelled contexts resulting in potential buggy outputs • Fixed a bug where outgoing voice messages might not be able to be played
133 lines
5.9 KiB
Swift
133 lines
5.9 KiB
Swift
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
import Foundation
|
|
import SessionUtilitiesKit
|
|
|
|
extension Network.SOGS {
|
|
public struct Message: Codable, Equatable, Hashable {
|
|
enum CodingKeys: String, CodingKey {
|
|
case id
|
|
case sender = "session_id"
|
|
case posted
|
|
case edited
|
|
case deleted
|
|
case seqNo = "seqno"
|
|
case whisper
|
|
case whisperMods = "whisper_mods"
|
|
case whisperTo = "whisper_to"
|
|
|
|
case base64EncodedData = "data"
|
|
case base64EncodedSignature = "signature"
|
|
|
|
case reactions = "reactions"
|
|
}
|
|
|
|
public let id: Int64
|
|
public let sender: String?
|
|
public let posted: TimeInterval?
|
|
public let edited: TimeInterval?
|
|
public let deleted: Bool?
|
|
public let seqNo: Int64
|
|
public let whisper: Bool
|
|
public let whisperMods: Bool
|
|
public let whisperTo: String?
|
|
|
|
public let base64EncodedData: String?
|
|
public let base64EncodedSignature: String?
|
|
|
|
public struct Reaction: Codable, Equatable, Hashable {
|
|
enum CodingKeys: String, CodingKey {
|
|
case count
|
|
case reactors
|
|
case you
|
|
case index
|
|
}
|
|
|
|
public let count: Int64
|
|
public let reactors: [String]?
|
|
public let you: Bool
|
|
public let index: Int64
|
|
}
|
|
|
|
public let reactions: [String: Reaction]?
|
|
}
|
|
}
|
|
|
|
// MARK: - Decoder
|
|
|
|
extension Network.SOGS.Message {
|
|
public init(from decoder: Decoder) throws {
|
|
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
|
|
|
let maybeSender: String? = try container.decodeIfPresent(String.self, forKey: .sender)
|
|
let maybeBase64EncodedData: String? = try container.decodeIfPresent(String.self, forKey: .base64EncodedData)
|
|
let maybeBase64EncodedSignature: String? = try container.decodeIfPresent(String.self, forKey: .base64EncodedSignature)
|
|
let maybeReactions: [String: Reaction]? = try container.decodeIfPresent([String: Reaction].self, forKey: .reactions)
|
|
|
|
// If we have data and a signature (ie. the message isn't a deletion) then validate the signature
|
|
if let base64EncodedData: String = maybeBase64EncodedData, let base64EncodedSignature: String = maybeBase64EncodedSignature {
|
|
guard let sender: String = maybeSender, let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else {
|
|
throw NetworkError.parsingFailed
|
|
}
|
|
|
|
// Verify the signature based on the SessionId.Prefix type
|
|
let maybeSenderSessionId: SessionId? = try? SessionId(from: sender)
|
|
let dependencies: Dependencies = try decoder.dependencies ?? { throw DependenciesError.missingDependencies }()
|
|
|
|
switch (maybeSenderSessionId, maybeSenderSessionId?.prefix) {
|
|
case (.some(let sessionId), .blinded15), (.some(let sessionId), .blinded25):
|
|
guard
|
|
dependencies[singleton: .crypto].verify(
|
|
.signature(message: data.bytes, publicKey: sessionId.publicKey, signature: signature.bytes)
|
|
)
|
|
else {
|
|
Log.info("Ignoring message with invalid signature.")
|
|
throw NetworkError.parsingFailed
|
|
}
|
|
|
|
case (.some(let sessionId), .standard), (.some(let sessionId), .unblinded):
|
|
guard
|
|
dependencies[singleton: .crypto].verify(
|
|
.signatureXed25519(signature, curve25519PublicKey: sessionId.publicKey, data: data)
|
|
)
|
|
else {
|
|
Log.info("Ignoring message with invalid signature.")
|
|
throw NetworkError.parsingFailed
|
|
}
|
|
|
|
case (.some, .none), (.none, _), (_, .group), (_, .versionBlinded07):
|
|
Log.info("Ignoring message with invalid sender.")
|
|
throw NetworkError.parsingFailed
|
|
}
|
|
}
|
|
|
|
self = Network.SOGS.Message(
|
|
id: try container.decode(Int64.self, forKey: .id),
|
|
sender: try container.decodeIfPresent(String.self, forKey: .sender),
|
|
posted: try container.decodeIfPresent(TimeInterval.self, forKey: .posted),
|
|
edited: try container.decodeIfPresent(TimeInterval.self, forKey: .edited),
|
|
deleted: try container.decodeIfPresent(Bool.self, forKey: .deleted),
|
|
seqNo: try container.decode(Int64.self, forKey: .seqNo),
|
|
whisper: ((try container.decodeIfPresent(Bool.self, forKey: .whisper)) ?? false),
|
|
whisperMods: ((try container.decodeIfPresent(Bool.self, forKey: .whisperMods)) ?? false),
|
|
whisperTo: try container.decodeIfPresent(String.self, forKey: .whisperTo),
|
|
base64EncodedData: maybeBase64EncodedData,
|
|
base64EncodedSignature: maybeBase64EncodedSignature,
|
|
reactions: !container.contains(.reactions) ? nil : (maybeReactions ?? [:])
|
|
)
|
|
}
|
|
}
|
|
|
|
extension Network.SOGS.Message.Reaction {
|
|
public init(from decoder: Decoder) throws {
|
|
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
|
|
|
self = Network.SOGS.Message.Reaction(
|
|
count: try container.decode(Int64.self, forKey: .count),
|
|
reactors: try container.decodeIfPresent([String].self, forKey: .reactors),
|
|
you: ((try container.decodeIfPresent(Bool.self, forKey: .you)) ?? false),
|
|
index: (try container.decode(Int64.self, forKey: .index))
|
|
)
|
|
}
|
|
}
|