diff --git a/Package.swift b/Package.swift index 15e1617..a88b736 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ import PackageDescription let package = Package( name: "AppStoreServerLibrary", platforms: [ - .macOS(.v11), // And other server environments + .macOS(.v13), // And other server environments ], products: [ .library( @@ -18,7 +18,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-certificates.git", from: "1.0.0"), .package(url: "https://github.com/apple/swift-asn1.git", from: "1.1.0"), .package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "4.0.0"), - .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.0.0"), + .package(url: "https://github.com/vapor/jwt-kit.git", from: "5.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), .package(url: "https://github.com/apple/swift-nio", from: "2.0.0"), .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.9.0"), diff --git a/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift b/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift index c1aff08..77a832f 100644 --- a/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift +++ b/Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift @@ -76,7 +76,7 @@ public class AppStoreServerAPIClient { } var urlRequest = HTTPClientRequest(url: url.absoluteString) - let token = try generateToken() + let token = try await generateToken() urlRequest.headers.add(name: "User-Agent", value: AppStoreServerAPIClient.userAgent) urlRequest.headers.add(name: "Authorization", value: "Bearer \(token)") urlRequest.headers.add(name: "Accept", value: "application/json") @@ -141,8 +141,8 @@ public class AppStoreServerAPIClient { } } - private func generateToken() throws -> String { - let signers = JWTSigners() + private func generateToken() async throws -> String { + let keys = JWTKeyCollection() let payload = AppStoreServerAPIJWT( exp: .init(value: Date().addingTimeInterval(5 * 60)), // 5 minutes iss: .init(value: self.issuerId), @@ -150,9 +150,8 @@ public class AppStoreServerAPIClient { aud: .init(value: AppStoreServerAPIClient.appStoreConnectAudience), iat: .init(value: Date()) ) - let key: ECDSAKey = try ECDSAKey.private(pem: self.signingKey.pemRepresentation) - signers.use(.es256(key: key)) - return try signers.sign(payload, typ: "JWT", kid: JWKIdentifier(stringLiteral: self.keyId)) + try await keys.add(ecdsa: ECDSA.PrivateKey(backing: signingKey)) + return try await keys.sign(payload, header: ["typ": "JWT", "kid": .string(self.keyId)]) } ///Uses a subscription’s product identifier to extend the renewal date for all of its eligible active subscribers. @@ -333,7 +332,8 @@ public class AppStoreServerAPIClient { var bid: String var aud: AudienceClaim var iat: IssuedAtClaim - func verify(using signer: JWTSigner) throws { + + func verify(using algorithm: some JWTAlgorithm) async throws { fatalError("Do not attempt to locally verify a JWT") } } diff --git a/Sources/AppStoreServerLibrary/ChainVerifier.swift b/Sources/AppStoreServerLibrary/ChainVerifier.swift index 3c0fed3..de39f3d 100644 --- a/Sources/AppStoreServerLibrary/ChainVerifier.swift +++ b/Sources/AppStoreServerLibrary/ChainVerifier.swift @@ -70,9 +70,9 @@ struct ChainVerifier { return VerificationResult.invalid(VerificationError.VERIFICATION_FAILURE) } // Verify using Vapor - let signers = JWTSigners() - try signers.use(.es256(key: .public(pem: publicKey.pemRepresentation))) - let verifiedBody: VerificationResult = try VerificationResult.valid(signers.verify(signedData)) + let keys = JWTKeyCollection() + await keys.add(ecdsa: try ECDSA.PublicKey(backing: publicKey)) + let verifiedBody: VerificationResult = try await VerificationResult.valid(keys.verify(signedData)) switch verifiedBody { case .invalid(_): return VerificationResult.invalid(VerificationError.VERIFICATION_FAILURE) @@ -100,8 +100,8 @@ struct ChainVerifier { } } -class VaporBody : JWTPayload { - func verify(using signer: JWTKit.JWTSigner) throws { +struct VaporBody : JWTPayload { + func verify(using algorithm: some JWTAlgorithm) async throws { // No-op } } diff --git a/Tests/AppStoreServerLibraryTests/TestingUtility.swift b/Tests/AppStoreServerLibraryTests/TestingUtility.swift index fb7a58c..e33f851 100644 --- a/Tests/AppStoreServerLibraryTests/TestingUtility.swift +++ b/Tests/AppStoreServerLibraryTests/TestingUtility.swift @@ -40,19 +40,19 @@ public class TestingUtility { public static func createSignedDataFromJson(_ path: String) -> String { let payload = readFile(path) let signingKey = Crypto.P256.Signing.PrivateKey() - let signer: JWTSigner = try! .es256(key: .private(pem: signingKey.pemRepresentation)) let header = JWTHeader(alg: "ES256") let encoder = JSONEncoder() let headerData = try! encoder.encode(header) - let encodedHeader = headerData.base64EncodedString() + let encodedHeader = base64ToBase64URL(headerData.base64EncodedString()) - let encodedPayload = payload.data(using: .utf8)!.base64EncodedString() - - let signature = try! signer.algorithm.sign("\(encodedHeader).\(encodedPayload)".data(using: .utf8)!) + let encodedPayload = base64ToBase64URL(payload.data(using: .utf8)!.base64EncodedString()) + + var signingInput = "\(encodedHeader).\(encodedPayload)" + let signature = try! signingInput.withUTF8 { try signingKey.signature(for: $0) } - return "\(base64ToBase64URL(encodedHeader)).\(base64ToBase64URL(encodedPayload)).\(base64ToBase64URL(Data(signature).base64EncodedString()))"; + return "\(signingInput).\(base64ToBase64URL(signature.rawRepresentation.base64EncodedString()))"; } private static func base64ToBase64URL(_ encodedString: String) -> String {