// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import Foundation import CryptoKit import GRDB import SessionUtilitiesKit public struct ClosedGroupKeyPair: Codable, Equatable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible { public static var databaseTableName: String { "closedGroupKeyPair" } internal static let closedGroupForeignKey = ForeignKey( [Columns.threadId], to: [ClosedGroup.Columns.threadId] ) private static let closedGroup = belongsTo(ClosedGroup.self, using: closedGroupForeignKey) public typealias Columns = CodingKeys public enum CodingKeys: String, CodingKey, ColumnExpression { case threadId case publicKey case secretKey case receivedTimestamp case threadKeyPairHash } public let threadId: String public let publicKey: Data public let secretKey: Data public let receivedTimestamp: TimeInterval public let threadKeyPairHash: String // MARK: - Relationships public var closedGroup: QueryInterfaceRequest { request(for: ClosedGroupKeyPair.closedGroup) } // MARK: - Initialization public init( threadId: String, publicKey: Data, secretKey: Data, receivedTimestamp: TimeInterval ) { self.threadId = threadId self.publicKey = publicKey self.secretKey = secretKey self.receivedTimestamp = receivedTimestamp // This value has a unique constraint and is used for key de-duping so the formula // shouldn't be modified unless all existing keys have their values updated self.threadKeyPairHash = Insecure.MD5 .hash(data: threadId.bytes + publicKey.bytes + secretKey.bytes) .hexString } } // MARK: - GRDB Interactions public extension ClosedGroupKeyPair { static func fetchLatestKeyPair(_ db: Database, threadId: String) throws -> ClosedGroupKeyPair? { return try ClosedGroupKeyPair .filter(Columns.threadId == threadId) .order(Columns.receivedTimestamp.desc) .fetchOne(db) } }