|  |  |  | // 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<ClosedGroup> { | 
					
						
							|  |  |  |         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 = Data(Insecure.MD5 | 
					
						
							|  |  |  |             .hash(data: threadId.bytes + publicKey.bytes + secretKey.bytes) | 
					
						
							|  |  |  |             .makeIterator()) | 
					
						
							|  |  |  |             .toHexString() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |