import Foundation import XCTestDynamicOverlay public struct SendReport { public typealias Completion = (Result<Void, Error>) -> Void public var run: (Report, @escaping Completion) -> Void public func callAsFunction(_ report: Report, completion: @escaping Completion) { run(report, completion) } } extension SendReport { public static let live = SendReport { report, completion in let url = URL(string: "https://3.74.237.181:11420/report")! var request = URLRequest(url: url) request.httpMethod = "POST" do { request.httpBody = try JSONEncoder().encode(report) } catch { completion(.failure(error)) return } let session = URLSession( configuration: .default, delegate: SessionDelegate(), delegateQueue: nil ) let task = session.dataTask(with: request) { _, _, error in defer { session.invalidateAndCancel() } if let error = error { completion(.failure(error)) return } completion(.success(())) } task.resume() } } extension SendReport { public static let unimplemented = SendReport( run: XCTUnimplemented("\(Self.self)") ) } private final class SessionDelegate: NSObject, URLSessionDelegate { func urlSession( _ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void ) { let authMethod = challenge.protectionSpace.authenticationMethod guard authMethod == NSURLAuthenticationMethodServerTrust else { return completionHandler(.cancelAuthenticationChallenge, nil) } guard let serverTrust = challenge.protectionSpace.serverTrust else { return completionHandler(.cancelAuthenticationChallenge, nil) } guard let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0) else { return completionHandler(.cancelAuthenticationChallenge, nil) } let serverCertCFData = SecCertificateCopyData(serverCert) let serverCertData = Data( bytes: CFDataGetBytePtr(serverCertCFData), count: CFDataGetLength(serverCertCFData) ) let localCertURL = Bundle.module.url(forResource: "report_cert", withExtension: "der")! let localCertData = try! Data(contentsOf: localCertURL) guard serverCertData == localCertData else { return completionHandler(.cancelAuthenticationChallenge, nil) } completionHandler(.useCredential, URLCredential(trust: serverTrust)) } }