diff --git a/.travis.yml b/.travis.yml index 225f25f..2c00dc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,16 @@ os: - osx - linux -osx_image: xcode9 +osx_image: xcode9.4 language: generic sudo: required dist: trusty + env: global: - SWIFT_VERSION=4.0 + - SWIFT_VERSION=4.1.2 matrix: - - SWIFTPM_BUILD=true - SWIFTPM_TEST=true - XCODE_TEST_SDK=macosx - XCODE_BUILD_SDK=iphonesimulator @@ -18,12 +19,6 @@ env: matrix: exclude: - # No need to build and test on macOS - - os: osx - env: SWIFTPM_BUILD=true - # LinuxMain.swift is out of sync - - os: linux - env: SWIFTPM_TEST=true - os: linux env: XCODE_TEST_SDK=macosx - os: linux @@ -37,7 +32,6 @@ install: - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" script: -- if [ -n "$SWIFTPM_BUILD" ]; then swift build; fi - if [ -n "$SWIFTPM_TEST" ]; then swift test; fi - if [ -n "$XCODE_BUILD_SDK" ] || [ -n "$XCODE_TEST_SDK" ]; then swift package generate-xcodeproj; fi - if [ -n "$XCODE_BUILD_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk $XCODE_BUILD_SDK; fi diff --git a/Package.swift b/Package.swift index 5ba29b4..01b5e95 100644 --- a/Package.swift +++ b/Package.swift @@ -4,14 +4,18 @@ import PackageDescription #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +#if canImport(CommonCrypto) +let dependencies: [Package.Dependency] = [] +#else let dependencies = [ Package.Dependency.package(url: "https://github.com/kylef-archive/CommonCrypto.git", from: "1.0.0"), ] +#endif let excludes = ["HMAC/HMACCryptoSwift.swift"] let targetDependencies: [Target.Dependency] = [] #else let dependencies = [ - Package.Dependency.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "0.8.0"), + Package.Dependency.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "0.10.0"), ] let excludes = ["HMAC/HMACCommonCrypto.swift"] let targetDependencies: [Target.Dependency] = ["CryptoSwift"] diff --git a/Sources/JWA/HMAC/HMACCommonCrypto.swift b/Sources/JWA/HMAC/HMACCommonCrypto.swift index 299fd8a..6dffce0 100644 --- a/Sources/JWA/HMAC/HMACCommonCrypto.swift +++ b/Sources/JWA/HMAC/HMACCommonCrypto.swift @@ -5,7 +5,7 @@ import CommonCrypto extension HMACAlgorithm: SignAlgorithm, VerifyAlgorithm { public func sign(_ message: Data) -> Data { let context = UnsafeMutablePointer.allocate(capacity: 1) - defer { context.deallocate(capacity: 1) } + defer { context.deallocate() } key.withUnsafeBytes() { (buffer: UnsafePointer) in CCHmacInit(context, hash.commonCryptoAlgorithm, buffer, size_t(key.count)) diff --git a/Sources/JWT/ClaimSet.swift b/Sources/JWT/ClaimSet.swift index 114c04e..4b253be 100644 --- a/Sources/JWT/ClaimSet.swift +++ b/Sources/JWT/ClaimSet.swift @@ -6,6 +6,11 @@ func parseTimeInterval(_ value: Any?) -> Date? { if let string = value as? String, let interval = TimeInterval(string) { return Date(timeIntervalSince1970: interval) } + + if let interval = value as? Int { + let double = Double(interval) + return Date(timeIntervalSince1970: double) + } if let interval = value as? TimeInterval { return Date(timeIntervalSince1970: interval) @@ -104,7 +109,7 @@ extension ClaimSet { try validateAudience(audience) } - try validateExpiary(leeway: leeway) + try validateExpiry(leeway: leeway) try validateNotBefore(leeway: leeway) try validateIssuedAt(leeway: leeway) } @@ -132,8 +137,13 @@ extension ClaimSet { throw InvalidToken.invalidIssuer } } - + + @available(*, deprecated, message: "This method's name is misspelled. Please instead use validateExpiry(leeway:).") public func validateExpiary(leeway: TimeInterval = 0) throws { + try validateExpiry(leeway: leeway) + } + + public func validateExpiry(leeway: TimeInterval = 0) throws { try validateDate(claims, key: "exp", comparison: .orderedAscending, leeway: (-1 * leeway), failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") } diff --git a/Sources/JWT/Decode.swift b/Sources/JWT/Decode.swift index 0e2b6d0..b6aa428 100644 --- a/Sources/JWT/Decode.swift +++ b/Sources/JWT/Decode.swift @@ -63,18 +63,6 @@ public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, aud return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer, leeway: leeway) } -/// Decode a JWT -@available(*, deprecated, message: "use decode that returns a ClaimSet instead") -public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> Payload { - return try decode(jwt, algorithms: algorithms, verify: verify, audience: audience, issuer: issuer).claims -} - -/// Decode a JWT -@available(*, deprecated, message: "use decode that returns a ClaimSet instead") -public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> Payload { - return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer).claims -} - // MARK: Parsing a JWT func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signature: Data, signatureInput: String) { diff --git a/Sources/JWT/Encode.swift b/Sources/JWT/Encode.swift index 643c827..22d1960 100644 --- a/Sources/JWT/Encode.swift +++ b/Sources/JWT/Encode.swift @@ -38,14 +38,3 @@ public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> Void)) closure(builder) return encode(claims: builder.claims, algorithm: algorithm) } - - -/*** Encode a payload - - parameter payload: The payload to sign - - parameter algorithm: The algorithm to sign the payload with - - returns: The JSON web token as a String - */ -@available(*, deprecated, message: "use encode(claims: algorithm:) instead") -public func encode(_ payload: Payload, algorithm: Algorithm) -> String { - return encode(claims: ClaimSet(claims: payload), algorithm: algorithm) -} diff --git a/Tests/JWTTests/ClaimSetTests.swift b/Tests/JWTTests/ClaimSetTests.swift index 594e648..aa8e8dd 100644 --- a/Tests/JWTTests/ClaimSetTests.swift +++ b/Tests/JWTTests/ClaimSetTests.swift @@ -7,7 +7,7 @@ class ValidationTests: XCTestCase { claims.expiration = Date().addingTimeInterval(-1) do { - try claims.validateExpiary() + try claims.validateExpiry() XCTFail("InvalidToken.expiredSignature error should have been thrown.") } catch InvalidToken.expiredSignature { // Correct error thrown @@ -21,7 +21,7 @@ class ValidationTests: XCTestCase { claims.expiration = Date().addingTimeInterval(-1) do { - try claims.validateExpiary(leeway: 2) + try claims.validateExpiry(leeway: 2) } catch { XCTFail("Unexpected error while validating exp claim that should be valid with leeway.") } diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index 24a17b3..cde1a10 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -1,19 +1,12 @@ import Foundation import XCTest -import JWT +@testable import JWT class DecodeTests: XCTestCase { - func testDecodingValidJWTAsClaimSet() throws { - let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - XCTAssertEqual(claims["name"] as? String, "Kyle") - } - func testDecodingValidJWT() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims["name"] as? String, "Kyle") } @@ -25,7 +18,7 @@ class DecodeTests: XCTestCase { func testDisablingVerify() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - _ = try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li") as ClaimSet + _ = try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li") } // MARK: Issuer claim @@ -33,7 +26,7 @@ class DecodeTests: XCTestCase { func testSuccessfulIssuerValidation() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.issuer, "fuller.li") } @@ -54,7 +47,7 @@ class DecodeTests: XCTestCase { XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } - func testInvalidExpiaryClaim() { + func testInvalidExpiryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } @@ -63,15 +56,15 @@ class DecodeTests: XCTestCase { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) } func testUnexpiredClaimString() throws { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) } @@ -80,14 +73,14 @@ class DecodeTests: XCTestCase { func testNotBeforeClaim() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720) } func testNotBeforeClaimString() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720) } @@ -107,14 +100,14 @@ class DecodeTests: XCTestCase { func testIssuedAtClaimInThePast() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720) } func testIssuedAtClaimInThePastString() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" - let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720) } @@ -185,24 +178,24 @@ class DecodeTests: XCTestCase { func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" - assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: String], ["some": "payload"]) + assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { claims in + XCTAssertEqual(claims as! [String: String], ["some": "payload"]) } } } // MARK: Helpers -func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure: ((Payload) -> Void)? = nil) { +func assertSuccess(_ decoder: @autoclosure () throws -> ClaimSet, closure: (([String: Any]) -> Void)? = nil) { do { - let payload = try decoder() - closure?(payload) + let claims = try decoder() + closure?(claims.claims as [String: Any]) } catch { XCTFail("Failed to decode while expecting success. \(error)") } } -func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure: ((InvalidToken) -> Void)? = nil) { +func assertFailure(_ decoder: @autoclosure () throws -> ClaimSet, closure: ((InvalidToken) -> Void)? = nil) { do { _ = try decoder() XCTFail("Decoding succeeded, expected a failure.") @@ -213,7 +206,7 @@ func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure: ((Inva } } -func assertDecodeError(_ decoder: @autoclosure () throws -> Payload, error: String) { +func assertDecodeError(_ decoder: @autoclosure () throws -> ClaimSet, error: String) { assertFailure(try decoder()) { failure in switch failure { case .decodeError(let decodeError): diff --git a/Tests/JWTTests/JWTEncodeTests.swift b/Tests/JWTTests/JWTEncodeTests.swift index 0dbb7b3..9ff7f14 100644 --- a/Tests/JWTTests/JWTEncodeTests.swift +++ b/Tests/JWTTests/JWTEncodeTests.swift @@ -6,31 +6,53 @@ class JWTEncodeTests: XCTestCase { func testEncodingJWT() { let payload = ["name": "Kyle"] as Payload let jwt = JWT.encode(claims: payload, algorithm: .hs256("secret".data(using: .utf8)!)) - + let expected = [ // { "alg": "HS256", "typ": "JWT" } "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg", - + // { "typ": "JWT", "alg": "HS256" } - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiS3lsZSJ9.4tCpoxfyfjbUyLjm9_zu-r52Vxn6bFq9kp6Rt9xMs4A", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiS3lsZSJ9.4tCpoxfyfjbUyLjm9_zu-r52Vxn6bFq9kp6Rt9xMs4A" ] - + XCTAssertTrue(expected.contains(jwt)) } - + func testEncodingWithBuilder() { let algorithm = Algorithm.hs256("secret".data(using: .utf8)!) let jwt = JWT.encode(algorithm) { builder in builder.issuer = "fuller.li" } - - XCTAssertEqual(jwt, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ") + + let expected = [ + // { "alg": "HS256", "typ": "JWT" } + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ", + // { "typ": "JWT", "alg": "HS256" } + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.x5Fdll-kZBImOPtpT1fZH_8hDW01Ax3pbZx_EiljoLk" + ] + + XCTAssertTrue(expected.contains(jwt)) } - + func testEncodingClaimsWithHeaders() { let algorithm = Algorithm.hs256("secret".data(using: .utf8)!) let jwt = JWT.encode(claims: ClaimSet(), algorithm: algorithm, headers: ["kid": "x"]) - - XCTAssertEqual(jwt, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IngifQ.e30.ddEotxYYMMdat5HPgYFQnkHRdPXsxPG71ooyhIUoqGA") + + let expected = [ + // { "alg": "HS256", "typ": "JWT", "kid": "x" } + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IngifQ.e30.ddEotxYYMMdat5HPgYFQnkHRdPXsxPG71ooyhIUoqGA", + // { "alg": "HS256", "kid": "x", "typ": "JWT" } + "eyJhbGciOiJIUzI1NiIsImtpZCI6IngiLCJ0eXAiOiJKV1QifQ.e30.xiT6fWe5dWGeuq8zFb0je_14Maa_9mHbVPSyJhUIJ54", + // { "typ": "JWT", "alg": "HS256", "kid": "x" } + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IngifQ.e30.5t6a61tpSXFo5QBHYCnKAz2mTHrW9kaQ9n_b7e-jWw0", + // { "typ": "JWT", "kid": "x", "alg": "HS256" } + "eyJ0eXAiOiJKV1QiLCJraWQiOiJ4IiwiYWxnIjoiSFMyNTYifQ.e30.DG5nmV2CVH6mV_iEm0xXZvL0DUJ22ek2xy6fNi_pGLc", + // { "kid": "x", "typ": "JWT", "alg": "HS256" } + "eyJraWQiOiJ4IiwidHlwIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.e30.h5ZvlqECBIvu9uocR5_5uF3wnhga8vTruvXpzaHpRdA", + // { "kid": "x", "alg": "HS256", "typ": "JWT" } + "eyJraWQiOiJ4IiwiYWxnIjoiSFMyNTYiLCJ0eXAiOiJKV1QifQ.e30.5KqN7N5a7Cfbe2eKN41FJIfgMjcdSZ7Nt16xqlyOeMo" + ] + + XCTAssertTrue(expected.contains(jwt)) } } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 8488183..492555b 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -1,18 +1,51 @@ import XCTest +@testable import JWATests @testable import JWTTests +extension HMACAlgorithmTests { + static var allTests: [(String, (HMACAlgorithmTests) -> () throws -> Void)] { + return [ + ("testSHA256Name", testSHA256Name), + ("testSHA384Name", testSHA384Name), + ("testSHA512Name", testSHA512Name), + ("testSHA256Sign", testSHA256Sign), + ("testSHA384Sign", testSHA384Sign), + ("testSHA512Sign", testSHA512Sign), + ("testSHA256Verify", testSHA256Verify), + ("testSHA384Verify", testSHA384Verify), + ("testSHA512Verify", testSHA512Verify) + ] + } +} -extension EncodeTests { - static var allTests: [(String, (EncodeTests) -> (Void) throws -> Void)] { +extension NoneAlgorithmTests { + static var allTests: [(String, (NoneAlgorithmTests) -> () throws -> Void)] { return [ - ("testEncodingJWT", testEncodingJWT), - ("testEncodingWithBuilder", testEncodingWithBuilder), + ("testName", testName), + ("testSign", testSign), + ("testVerify", testVerify) ] } } +extension CompactJSONDecoderTests { + static var allTests: [(String, (CompactJSONDecoderTests) -> () throws -> Void)] { + return [ + ("testDecoder", testDecoder) + ] + } +} + +extension CompactJSONEncoderTests { + static var allTests: [(String, (CompactJSONEncoderTests) -> () throws -> Void)] { + return [ + ("testEncode", testEncode) + ] + } +} + extension DecodeTests { - static var allTests: [(String, (DecodeTests) -> (Void) throws -> Void)] { + static var allTests: [(String, (DecodeTests) -> () throws -> Void)] { return [ ("testDecodingValidJWT", testDecodingValidJWT), ("testFailsToDecodeInvalidStringWithoutThreeSegments", testFailsToDecodeInvalidStringWithoutThreeSegments), @@ -21,7 +54,7 @@ extension DecodeTests { ("testIncorrectIssuerValidation", testIncorrectIssuerValidation), ("testMissingIssuerValidation", testMissingIssuerValidation), ("testExpiredClaim", testExpiredClaim), - ("testInvalidExpiaryClaim", testInvalidExpiaryClaim), + ("testInvalidExpiryClaim", testInvalidExpiryClaim), ("testUnexpiredClaim", testUnexpiredClaim), ("testUnexpiredClaimString", testUnexpiredClaimString), ("testNotBeforeClaim", testNotBeforeClaim), @@ -40,26 +73,64 @@ extension DecodeTests { ("testNoneFailsWithSecretAlgorithm", testNoneFailsWithSecretAlgorithm), ("testMatchesAnyAlgorithm", testMatchesAnyAlgorithm), ("testHS384Algorithm", testHS384Algorithm), - ("testHS512Algorithm", testHS512Algorithm), + ("testHS512Algorithm", testHS512Algorithm) ] } } +extension IntegrationTests { + static var allTests: [(String, (IntegrationTests) -> () throws -> Void)] { + return [ + ("testVerificationFailureWithoutLeeway", testVerificationFailureWithoutLeeway), + ("testVerificationSuccessWithLeeway", testVerificationSuccessWithLeeway) + ] + } +} + +extension JWTEncodeTests { + static var allTests: [(String, (JWTEncodeTests) -> () throws -> Void)] { + return [ + ("testEncodingJWT", testEncodingJWT), + ("testEncodingWithBuilder", testEncodingWithBuilder), + ("testEncodingClaimsWithHeaders", testEncodingClaimsWithHeaders) + ] + } +} + extension PayloadTests { - static var allTests: [(String, (PayloadTests) -> (Void) throws -> Void)] { + static var allTests: [(String, (PayloadTests) -> () throws -> Void)] { return [ ("testIssuer", testIssuer), ("testAudience", testAudience), ("testExpiration", testExpiration), ("testNotBefore", testNotBefore), ("testIssuedAt", testIssuedAt), - ("testCustomAttributes", testCustomAttributes), + ("testCustomAttributes", testCustomAttributes) ] } } +extension ValidationTests { + static var allTests: [(String, (ValidationTests) -> () throws -> Void)] { + return [ + ("testClaimJustExpiredWithoutLeeway", testClaimJustExpiredWithoutLeeway), + ("testClaimJustNotExpiredWithoutLeeway", testClaimJustNotExpiredWithoutLeeway), + ("testNotBeforeIsImmatureSignatureWithoutLeeway", testNotBeforeIsImmatureSignatureWithoutLeeway), + ("testNotBeforeIsValidWithLeeway", testNotBeforeIsValidWithLeeway), + ("testIssuedAtIsInFutureWithoutLeeway", testIssuedAtIsInFutureWithoutLeeway), + ("testIssuedAtIsValidWithLeeway", testIssuedAtIsValidWithLeeway) + ] + } +} + XCTMain([ - testCase(EncodeTests.allTests), + testCase(HMACAlgorithmTests.allTests), + testCase(NoneAlgorithmTests.allTests), + testCase(CompactJSONDecoderTests.allTests), + testCase(CompactJSONEncoderTests.allTests), testCase(DecodeTests.allTests), + testCase(IntegrationTests.allTests), + testCase(JWTEncodeTests.allTests), testCase(PayloadTests.allTests), + testCase(ValidationTests.allTests) ])