diff --git a/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift b/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift index 579264d..0d237aa 100644 --- a/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift +++ b/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift @@ -9,7 +9,7 @@ import NIOFoundationCompat public class AppStoreServerAPIClient { - public enum ConfigurationError: Error { + public enum ConfigurationError: Error, Hashable, Sendable { /// Xcode is not a supported environment for an AppStoreServerAPIClient case invalidEnvironment } @@ -345,7 +345,9 @@ public enum APIResult { case failure(statusCode: Int?, rawApiError: Int64?, apiError: APIError?, errorMessage: String?, causedBy: Error?) } -public enum APIError: Int64 { +extension APIResult: Sendable where T: Sendable {} + +public enum APIError: Int64, Hashable, Sendable { ///An error that indicates an invalid request. /// ///[GeneralBadRequestError](https://developer.apple.com/documentation/appstoreserverapi/generalbadrequesterror) @@ -633,7 +635,7 @@ public enum APIError: Int64 { case generalInternalRetryable = 5000001 } -public enum GetTransactionHistoryVersion: String { +public enum GetTransactionHistoryVersion: String, Hashable, Sendable { @available(*, deprecated) case v1 = "v1" case v2 = "v2" diff --git a/Sources/AppStoreServerLibrary/ChainVerifier.swift b/Sources/AppStoreServerLibrary/ChainVerifier.swift index 3d3ae67..8872699 100644 --- a/Sources/AppStoreServerLibrary/ChainVerifier.swift +++ b/Sources/AppStoreServerLibrary/ChainVerifier.swift @@ -8,8 +8,7 @@ import Crypto import AsyncHTTPClient import NIOFoundationCompat -class ChainVerifier { - +actor ChainVerifier { private static let EXPECTED_CHAIN_LENGTH = 3 private static let EXPECTED_JWT_SEGMENTS = 3 private static let EXPECTED_ALGORITHM = "ES256" @@ -28,7 +27,7 @@ class ChainVerifier { self.verifiedPublicKeyCache = [:] } - func verify(signedData: String, type: T.Type, onlineVerification: Bool, environment: AppStoreEnvironment) async -> VerificationResult where T: Decodable { + func verify(signedData: String, type: T.Type, onlineVerification: Bool, environment: AppStoreEnvironment) async -> VerificationResult where T: Decodable & Sendable { let header: JWTHeader; let decodedBody: T; do { @@ -120,7 +119,7 @@ class ChainVerifier { return verificationResult } - func verifyChainWithoutCaching(leaf: Certificate, intermediate: Certificate, online: Bool, validationTime: Date) async -> X509.VerificationResult { + nonisolated func verifyChainWithoutCaching(leaf: Certificate, intermediate: Certificate, online: Bool, validationTime: Date) async -> X509.VerificationResult { var verifier = Verifier(rootCertificates: self.store) { RFC5280Policy(validationTime: validationTime) AppStoreOIDPolicy() @@ -132,7 +131,7 @@ class ChainVerifier { return await verifier.validate(leafCertificate: leaf, intermediates: intermediateStore) } - func getDate() -> Date { + nonisolated func getDate() -> Date { return Date() } } @@ -226,6 +225,10 @@ public enum VerificationResult { case invalid(VerificationError) } +extension VerificationResult: Equatable where T: Equatable {} +extension VerificationResult: Hashable where T: Hashable {} +extension VerificationResult: Sendable where T: Sendable {} + public enum VerificationError: Hashable, Sendable { case INVALID_JWT_FORMAT case INVALID_CERTIFICATE diff --git a/Sources/AppStoreServerLibrary/SignedDataVerifier.swift b/Sources/AppStoreServerLibrary/SignedDataVerifier.swift index 2df7b3a..df008c5 100644 --- a/Sources/AppStoreServerLibrary/SignedDataVerifier.swift +++ b/Sources/AppStoreServerLibrary/SignedDataVerifier.swift @@ -3,9 +3,9 @@ import Foundation ///A verifier and decoder class designed to decode signed data from the App Store. -public struct SignedDataVerifier { +public struct SignedDataVerifier: Sendable { - public enum ConfigurationError: Error { + public enum ConfigurationError: Error, Hashable, Sendable { case INVALID_APP_APPLE_ID } @@ -148,7 +148,7 @@ public struct SignedDataVerifier { return appTransactionResult } - private func decodeSignedData(signedData: String, type: T.Type) async -> VerificationResult where T : Decodable { + private func decodeSignedData(signedData: String, type: T.Type) async -> VerificationResult where T : Decodable & Sendable { return await chainVerifier.verify(signedData: signedData, type: type, onlineVerification: self.enableOnlineChecks, environment: self.environment) } }