From b26e118c8c21133b81eeb91da6e2f6e5f29dc9bb Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 5 Apr 2015 23:24:59 +0100 Subject: [PATCH 001/127] Prevent none algorithm from being valid with a key configured --- JSONWebToken.podspec | 2 +- JWT/JWT.swift | 3 +++ JWTTests/JWTTests.swift | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index da42d2c..97d5e4a 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.0.0' + spec.version = '1.0.1' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 87780fc..3d70f62 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -13,6 +13,9 @@ public enum Algorithm : Printable { static func algorithm(name:String, key:String?) -> Algorithm? { if name == "none" { + if let key = key { + return nil // We don't allow nil when we configured a key + } return Algorithm.None } else if let key = key { if name == "HS256" { diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index bce0c29..75eedad 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -143,6 +143,11 @@ class JWTDecodeTests : XCTestCase { XCTAssertEqual(payload as NSDictionary, ["test": "ing"]) } } + + func testNoneFailsWithSecretAlgorithm() { + let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." + assertFailure(decode(jwt, key:"secret")) + } } // MARK: Helpers From 5dc3eade1e185b31c4e19454f81d2c4b519c5791 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 5 Apr 2015 23:51:51 +0100 Subject: [PATCH 002/127] Only verify with known algorithms --- JWT/Decode.swift | 30 ++++++++++++-------------- JWTTests/JWTTests.swift | 48 +++++++++++++++++++++++------------------ README.md | 10 ++++++++- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/JWT/Decode.swift b/JWT/Decode.swift index 6519107..f44aa21 100644 --- a/JWT/Decode.swift +++ b/JWT/Decode.swift @@ -9,9 +9,6 @@ public enum InvalidToken : Printable { /// The JWT uses an unsupported algorithm case InvalidAlgorithm - /// An invalid key was used when trying to validate a JWT - case InvalidKey - /// The issued claim has expired case ExpiredSignature @@ -43,9 +40,7 @@ public enum InvalidToken : Printable { case InvalidAudience: return "Invalid Audience" case InvalidAlgorithm: - return "Unsupported Algorithm" - case InvalidKey: - return "Invalid Key" + return "Unsupported algorithm or incorrect key" } } } @@ -60,13 +55,12 @@ public enum DecodeResult { case Failure(InvalidToken) } - /// Decode a JWT -public func decode(jwt:String, key:String? = nil, verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult { +public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult { switch load(jwt) { case let .Success(header, payload, signature, signatureInput): if verify { - if let failure = validateClaims(payload, audience, issuer) ?? verifySignature(header, signatureInput, signature, key) { + if let failure = validateClaims(payload, audience, issuer) ?? verifySignature(algorithms, header, signatureInput, signature) { return .Failure(failure) } } @@ -77,6 +71,11 @@ public func decode(jwt:String, key:String? = nil, verify:Bool = true, audience:S } } +/// Decode a JWT +public func decode(jwt:String, algorithm:Algorithm, verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult { + return decode(jwt, [algorithm], verify: verify, audience: audience, issuer: issuer) +} + // MARK: Parsing a JWT enum LoadResult { @@ -125,14 +124,13 @@ func load(jwt:String) -> LoadResult { // MARK: Signature Verification -func verifySignature(header:Payload, signingInput:String, signature:NSData, key:String?) -> InvalidToken? { +func verifySignature(algorithms:[Algorithm], header:Payload, signingInput:String, signature:NSData) -> InvalidToken? { if let alg = header["alg"] as? String { - if let algoritm = Algorithm.algorithm(alg, key: key) { - if algoritm.verify(signingInput, signature: signature) { - return nil - } else { - return .InvalidKey - } + let matchingAlgorithms = filter(algorithms) { algorithm in algorithm.description == alg } + let results = map(matchingAlgorithms) { algorithm in algorithm.verify(signingInput, signature: signature) } + let successes = filter(results) { $0 } + if successes.count > 0 { + return nil } return .InvalidAlgorithm diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 75eedad..55b78d4 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -13,57 +13,58 @@ class JWTEncodeTests : XCTestCase { class JWTDecodeTests : XCTestCase { func testDecodingValidJWT() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - assertSuccess(decode(jwt, key:"secret")) { payload in + let result = JWT.decode(jwt, .HS256("secret")) + assertSuccess(result) { payload in XCTAssertEqual(payload as NSDictionary, ["name": "Kyle"]) } } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - assertDecodeError(decode("a.b"), "Not enough segments") + assertDecodeError(decode("a.b", .None), "Not enough segments") } // MARK: Disable verify func testDisablingVerify() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertSuccess(decode(jwt, verify:false, issuer:"fuller.li")) + assertSuccess(decode(jwt, .None, verify:false, issuer:"fuller.li")) } // MARK: Issuer claim func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(decode(jwt, key:"secret", issuer:"fuller.li")) { payload in + assertSuccess(decode(jwt, .HS256("secret"), issuer:"fuller.li")) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(decode(jwt, key:"secret", issuer:"querykit.org")) + assertFailure(decode(jwt, .HS256("secret"), issuer:"querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(decode(jwt, key:"secret", issuer:"fuller.li")) + assertFailure(decode(jwt, .HS256("secret"), issuer:"fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - assertFailure(decode(jwt, key:"secret")) + assertFailure(decode(jwt, .HS256("secret"))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - assertFailure(decode(jwt, key:"secret")) + assertFailure(decode(jwt, .HS256("secret"))) } func testUnexpiredClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - assertSuccess(decode(jwt, key:"secret")) { payload in + assertSuccess(decode(jwt, .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) } } @@ -72,27 +73,27 @@ class JWTDecodeTests : XCTestCase { func testNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - assertSuccess(decode(jwt, key:"secret")) { payload in + assertSuccess(decode(jwt, .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) } } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(decode(jwt, key:"secret"), "Not before claim (nbf) must be an integer") + assertDecodeError(decode(jwt, .HS256("secret")), "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - assertFailure(decode(jwt, key:"secret")) + assertFailure(decode(jwt, .HS256("secret"))) } // MARK: Issued at claim func testIssuedAtClaimInThePast() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - assertSuccess(decode(jwt, key:"secret")) { payload in + assertSuccess(decode(jwt, .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) } } @@ -100,53 +101,58 @@ class JWTDecodeTests : XCTestCase { func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - assertFailure(decode(jwt, key:"secret")) + assertFailure(decode(jwt, .HS256("secret"))) } func testInvalidIssuedAtClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOlsxNzI4MTg4NDkxXX0.ND7QMWtLkXDXH38OaXM3SQgLo3Z5TNgF_pcfWHV_alQ" - assertDecodeError(decode(jwt, key:"secret"), "Issued at claim (iat) must be an integer") + assertDecodeError(decode(jwt, .HS256("secret")), "Issued at claim (iat) must be an integer") } // MARK: Audience claims func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(decode(jwt, key:"secret", audience:"maxine")) { payload in + assertSuccess(decode(jwt, .HS256("secret"), audience:"maxine")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": ["maxine", "katie"]]) } } func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(decode(jwt, key:"secret", audience:"kyle")) { payload in + assertSuccess(decode(jwt, .HS256("secret"), audience:"kyle")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(decode(jwt, key:"secret", audience:"maxine")) + assertFailure(decode(jwt, .HS256("secret"), audience:"maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(decode(jwt, key:"secret", audience:"kyle")) + assertFailure(decode(jwt, .HS256("secret"), audience:"kyle")) } // MARK: Signature verification func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(decode(jwt)) { payload in + assertSuccess(decode(jwt, .None)) { payload in XCTAssertEqual(payload as NSDictionary, ["test": "ing"]) } } func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertFailure(decode(jwt, key:"secret")) + assertFailure(decode(jwt, .HS256("secret"))) + } + + func testMatchesAnyAlgorithm() { + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." + assertFailure(decode(jwt, [.HS256("anothersecret"), .HS256("secret")])) } } diff --git a/README.md b/README.md index 47b036f..bd70b8c 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,16 @@ JWT.encode(["my": "payload"], .HS256("secret")) ### Decoding a JWT +When decoding a JWT, you must supply one or more algorithms and keys. + +```swift +JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", .HS256("secret")) +``` + +When the JWT may be signed with one out of many algorithms or keys: + ```swift -JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w") +JWT.decode("eyJh...5w", [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) ``` #### Supported claims From 2b5bc6c504c6be52042da9188cdd97ac264dad31 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 5 Apr 2015 23:52:53 +0100 Subject: [PATCH 003/127] Release 1.1.0 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 97d5e4a..127aef9 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.0.1' + spec.version = '1.1.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 7455c9dc82e5f2bef69e866093a71189505a8821 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 6 Apr 2015 00:30:20 +0100 Subject: [PATCH 004/127] [Encoding] Introduce a builder pattern --- JWT/JWT.swift | 76 +++++++++++++++++++++++++++++++++++++++++ JWTTests/JWTTests.swift | 63 ++++++++++++++++++++++++++++++++++ README.md | 10 ++++++ 3 files changed, 149 insertions(+) diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 3d70f62..d59eb81 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -76,3 +76,79 @@ public func encode(payload:Payload, algorithm:Algorithm) -> String { let signature = algorithm.sign(signingInput) return "\(signingInput).\(signature)" } + +public class PayloadBuilder { + var payload = Payload() + + public var issuer:String? { + get { + return payload["iss"] as? String + } + set { + payload["iss"] = newValue + } + } + + public var audience:String? { + get { + return payload["aud"] as? String + } + set { + payload["aud"] = newValue + } + } + + public var expiration:NSDate? { + get { + if let expiration = payload["exp"] as? NSTimeInterval { + return NSDate(timeIntervalSince1970: expiration) + } + + return nil + } + set { + payload["exp"] = newValue?.timeIntervalSince1970 + } + } + + public var notBefore:NSDate? { + get { + if let notBefore = payload["nbf"] as? NSTimeInterval { + return NSDate(timeIntervalSince1970: notBefore) + } + + return nil + } + set { + payload["nbf"] = newValue?.timeIntervalSince1970 + } + } + + public var issuedAt:NSDate? { + get { + if let issuedAt = payload["iat"] as? NSTimeInterval { + return NSDate(timeIntervalSince1970: issuedAt) + } + + return nil + } + set { + payload["iat"] = newValue?.timeIntervalSince1970 + } + } + + public subscript(key: String) -> AnyObject? { + get { + return payload[key] + } + set { + payload[key] = newValue + } + } +} + +public func encode(algorithm:Algorithm, closure:(PayloadBuilder -> ())) -> String { + let builder = PayloadBuilder() + closure(builder) + return encode(builder.payload, algorithm) +} diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 55b78d4..1e442ed 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -8,6 +8,69 @@ class JWTEncodeTests : XCTestCase { let fixture = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" XCTAssertEqual(jwt, fixture) } + + func testEncodingWithBuilder() { + let algorithm = Algorithm.HS256("secret") + let jwt = JWT.encode(algorithm) { builder in + builder.issuer = "fuller.li" + } + + assertSuccess(JWT.decode(jwt, algorithm)) { payload in + XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) + } + } +} + +class JWTPayloadBuilder : XCTestCase { + func testIssuer() { + JWT.encode(.None) { builder in + builder.issuer = "fuller.li" + XCTAssertEqual(builder.issuer!, "fuller.li") + XCTAssertEqual(builder["iss"] as String, "fuller.li") + } + } + + func testAudience() { + JWT.encode(.None) { builder in + builder.audience = "cocoapods" + XCTAssertEqual(builder.audience!, "cocoapods") + XCTAssertEqual(builder["aud"] as String, "cocoapods") + } + } + + func testExpiration() { + JWT.encode(.None) { builder in + let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) + builder.expiration = date + XCTAssertEqual(builder.expiration!, date) + XCTAssertEqual(builder["exp"] as NSTimeInterval, date.timeIntervalSince1970) + } + } + + func testNotBefore() { + JWT.encode(.None) { builder in + let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) + builder.notBefore = date + XCTAssertEqual(builder.notBefore!, date) + XCTAssertEqual(builder["nbf"] as NSTimeInterval, date.timeIntervalSince1970) + } + } + + func testIssuedAt() { + JWT.encode(.None) { builder in + let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) + builder.issuedAt = date + XCTAssertEqual(builder.issuedAt!, date) + XCTAssertEqual(builder["iat"] as NSTimeInterval, date.timeIntervalSince1970) + } + } + + func testCustomAttributes() { + JWT.encode(.None) { builder in + builder["user"] = "kyle" + XCTAssertEqual(builder["user"] as String, "kyle") + } + } } class JWTDecodeTests : XCTestCase { diff --git a/README.md b/README.md index bd70b8c..c9cbc02 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,16 @@ import JWT JWT.encode(["my": "payload"], .HS256("secret")) ``` +#### Building a JWT with the builder pattern + +```swift +JWT.encode(.HS256("secret")) { builder in + builder.issuer = "fuller.li" + builder.issuedAt = NSDate() + builder["custom"] = "Hi" +} +``` + ### Decoding a JWT When decoding a JWT, you must supply one or more algorithms and keys. From aaa0cc44dec3d7a52202cc5b3e66f75142f58a7f Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 6 Apr 2015 00:30:34 +0100 Subject: [PATCH 005/127] Release 1.2.0 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 127aef9..a66e138 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.1.0' + spec.version = '1.2.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From c46268f78d749471e7e8ba28717609a59b300c33 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 16 Apr 2015 23:32:12 -0700 Subject: [PATCH 006/127] Support Swift 1.2 --- JSONWebToken.podspec | 2 +- JWT/Base64.swift | 4 ++-- JWT/JWT.swift | 8 +++++--- JWTTests/JWTTests.swift | 12 ++++++------ Podfile.lock | 8 ++++---- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index a66e138..6216fcf 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |spec| spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.requires_arc = true - spec.dependency 'CryptoSwift', '~> 0.0.8' + spec.dependency 'CryptoSwift', '0.0.10' spec.module_name = 'JWT' end diff --git a/JWT/Base64.swift b/JWT/Base64.swift index b9143ef..9700992 100644 --- a/JWT/Base64.swift +++ b/JWT/Base64.swift @@ -4,7 +4,7 @@ import Foundation /// URI Safe base64 encode func base64encode(input:NSData) -> String { let data = input.base64EncodedDataWithOptions(NSDataBase64EncodingOptions(0)) - let string = NSString(data: data, encoding: NSUTF8StringEncoding) as String + let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String return string .stringByReplacingOccurrencesOfString("+", withString: "-", options: NSStringCompareOptions(0), range: nil) .stringByReplacingOccurrencesOfString("/", withString: "_", options: NSStringCompareOptions(0), range: nil) @@ -13,7 +13,7 @@ func base64encode(input:NSData) -> String { /// URI Safe base64 decode func base64decode(input:String) -> NSData? { - let rem = countElements(input) % 4 + let rem = count(input) % 4 var ending = "" if rem > 0 { diff --git a/JWT/JWT.swift b/JWT/JWT.swift index d59eb81..2b4878d 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -42,9 +42,11 @@ public enum Algorithm : Printable { return "" case .HS256(let key): - let mac = Authenticator.HMAC(key: key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, variant:.sha256) - let result = mac.authenticate(message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)! - return base64encode(result) + let keyData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! + let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! + let mac = Authenticator.HMAC(key: keyData.arrayOfBytes(), variant:.sha256) + let result = mac.authenticate(messageData.arrayOfBytes())! + return base64encode(NSData.withBytes(result)) } } diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 1e442ed..bf9095a 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -26,7 +26,7 @@ class JWTPayloadBuilder : XCTestCase { JWT.encode(.None) { builder in builder.issuer = "fuller.li" XCTAssertEqual(builder.issuer!, "fuller.li") - XCTAssertEqual(builder["iss"] as String, "fuller.li") + XCTAssertEqual(builder["iss"] as! String, "fuller.li") } } @@ -34,7 +34,7 @@ class JWTPayloadBuilder : XCTestCase { JWT.encode(.None) { builder in builder.audience = "cocoapods" XCTAssertEqual(builder.audience!, "cocoapods") - XCTAssertEqual(builder["aud"] as String, "cocoapods") + XCTAssertEqual(builder["aud"] as! String, "cocoapods") } } @@ -43,7 +43,7 @@ class JWTPayloadBuilder : XCTestCase { let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) builder.expiration = date XCTAssertEqual(builder.expiration!, date) - XCTAssertEqual(builder["exp"] as NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder["exp"] as! NSTimeInterval, date.timeIntervalSince1970) } } @@ -52,7 +52,7 @@ class JWTPayloadBuilder : XCTestCase { let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) builder.notBefore = date XCTAssertEqual(builder.notBefore!, date) - XCTAssertEqual(builder["nbf"] as NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder["nbf"] as! NSTimeInterval, date.timeIntervalSince1970) } } @@ -61,14 +61,14 @@ class JWTPayloadBuilder : XCTestCase { let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) builder.issuedAt = date XCTAssertEqual(builder.issuedAt!, date) - XCTAssertEqual(builder["iat"] as NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder["iat"] as! NSTimeInterval, date.timeIntervalSince1970) } } func testCustomAttributes() { JWT.encode(.None) { builder in builder["user"] = "kyle" - XCTAssertEqual(builder["user"] as String, "kyle") + XCTAssertEqual(builder["user"] as! String, "kyle") } } } diff --git a/Podfile.lock b/Podfile.lock index d65ebdc..f8320c5 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,10 +1,10 @@ PODS: - - CryptoSwift (0.0.8) + - CryptoSwift (0.0.10) DEPENDENCIES: - - CryptoSwift (~> 0.0.8) + - CryptoSwift (= 0.0.10) SPEC CHECKSUMS: - CryptoSwift: 6d1b93af5b48e02e57366bfad28b00170af405ee + CryptoSwift: 3b886d001f50deb65623a8967d68f6b8bf8d9ba1 -COCOAPODS: 0.36.3 +COCOAPODS: 0.36.4 From 7813bd241d245f4adb317fa9cc0e0b03ad6505e7 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 16 Apr 2015 23:37:33 -0700 Subject: [PATCH 007/127] Support HS384 and HS512 Closes #4 --- JWT/JWT.swift | 34 +++++++++++++++++++++++++++++----- JWTTests/JWTTests.swift | 14 ++++++++++++++ README.md | 11 ++--------- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 2b4878d..9438118 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -11,6 +11,12 @@ public enum Algorithm : Printable { /// HMAC using SHA-256 hash algorithm case HS256(String) + /// HMAC using SHA-384 hash algorithm + case HS384(String) + + /// HMAC using SHA-512 hash algorithm + case HS512(String) + static func algorithm(name:String, key:String?) -> Algorithm? { if name == "none" { if let key = key { @@ -20,6 +26,10 @@ public enum Algorithm : Printable { } else if let key = key { if name == "HS256" { return .HS256(key) + } else if name == "HS384" { + return .HS384(key) + } else if name == "HS512" { + return .HS512(key) } } @@ -32,21 +42,35 @@ public enum Algorithm : Printable { return "none" case .HS256(let key): return "HS256" + case .HS384(let key): + return "HS384" + case .HS512(let key): + return "HS512" } } /// Sign a message using the algorithm func sign(message:String) -> String { + func signHS(key:String, variant:CryptoSwift.HMAC.Variant) -> String { + let keyData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! + let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! + let mac = Authenticator.HMAC(key: keyData.arrayOfBytes(), variant:variant) + let result = mac.authenticate(messageData.arrayOfBytes())! + return base64encode(NSData.withBytes(result)) + } + switch self { case .None: return "" case .HS256(let key): - let keyData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! - let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! - let mac = Authenticator.HMAC(key: keyData.arrayOfBytes(), variant:.sha256) - let result = mac.authenticate(messageData.arrayOfBytes())! - return base64encode(NSData.withBytes(result)) + return signHS(key, .sha256) + + case .HS384(let key): + return signHS(key, .sha384) + + case .HS512(let key): + return signHS(key, .sha512) } } diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index bf9095a..584b7e7 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -217,6 +217,20 @@ class JWTDecodeTests : XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." assertFailure(decode(jwt, [.HS256("anothersecret"), .HS256("secret")])) } + + func testHS384Algorithm() { + let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" + assertSuccess(decode(jwt, .HS384("secret"))) { payload in + XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) + } + } + + func testHS512Algorithm() { + let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" + assertSuccess(decode(jwt, .HS512("secret"))) { payload in + XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) + } + } } // MARK: Helpers diff --git a/README.md b/README.md index c9cbc02..f080b73 100644 --- a/README.md +++ b/README.md @@ -64,15 +64,8 @@ This library supports the following algorithms: - None - Unsecured JWTs - HS256 - HMAC using SHA-256 hash algorithm (default) - -#### Additional Algorithms - -Support for HS384 and HS512 can be found in the `algorithms-hs` branch which depends on an unreleased version of CryptoSwift. It can be installed via: - -```ruby -pod 'JSONWebToken', :git => 'https://github.com/kylef/JSONWebToken.swift.git', :branch => 'algorithms-hs' -pod 'CryptoSwift', :head -``` +- HS384 - HMAC using SHA-384 hash algorithm +- HS512 - HMAC using SHA-384 hash algorithm ## License From bc5dde7684bdddccaf17b8a3131635cb8b241a84 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 16 Apr 2015 23:38:21 -0700 Subject: [PATCH 008/127] Release 1.3.0 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 6216fcf..df08b5c 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.2.0' + spec.version = '1.3.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From cf2c5dff529c90adafe56df979157ddb75350cba Mon Sep 17 00:00:00 2001 From: "Samuel E. Giddins" Date: Mon, 20 Apr 2015 22:04:23 -0700 Subject: [PATCH 009/127] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f080b73..35faf35 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ This library supports the following algorithms: - None - Unsecured JWTs - HS256 - HMAC using SHA-256 hash algorithm (default) - HS384 - HMAC using SHA-384 hash algorithm -- HS512 - HMAC using SHA-384 hash algorithm +- HS512 - HMAC using SHA-512 hash algorithm ## License From 63cf8e8d17c8a8764799ab7bd807241a32b10c18 Mon Sep 17 00:00:00 2001 From: Dee Evans Date: Thu, 10 Sep 2015 15:05:20 -0600 Subject: [PATCH 010/127] Updated the readme to show a better example of decoding. I cant be the only one that can get confused on this. --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 35faf35..fc2dbd0 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,20 @@ JWT.encode(.HS256("secret")) { builder in When decoding a JWT, you must supply one or more algorithms and keys. ```swift -JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", .HS256("secret")) +let result = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", .HS256("secret")) + +switch result { +case .Success(let payload): + print(payload) +case .Failure(let failure): + print("decoding failed \(failure)") +} ``` When the JWT may be signed with one out of many algorithms or keys: ```swift -JWT.decode("eyJh...5w", [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) +let result = JWT.decode("eyJh...5w", [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) ``` #### Supported claims From a3423e6060ca6d7afbba2d304e89e30f4400507d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 18 Sep 2015 11:24:17 -0700 Subject: [PATCH 011/127] Migrate to Swift 2.0 --- .travis.yml | 1 + JSONWebToken.podspec | 2 +- JWT.xcodeproj/project.pbxproj | 18 +-------- JWT/Base64.swift | 16 ++++---- JWT/Claims.swift | 12 +++--- JWT/Decode.swift | 16 ++++---- JWT/JWT.swift | 26 ++++++------ JWTTests/JWTTests.swift | 76 +++++++++++++++++------------------ Podfile.lock | 8 ++-- README.md | 6 +-- 10 files changed, 84 insertions(+), 97 deletions(-) diff --git a/.travis.yml b/.travis.yml index 38d6b3d..5eb95e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: objective-c +osx_image: xcode7 before_install: - gem install cocoapods --no-document - gem install xcpretty --no-document diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index df08b5c..8d74163 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |spec| spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.requires_arc = true - spec.dependency 'CryptoSwift', '0.0.10' + spec.dependency 'CryptoSwift', '0.0.14' spec.module_name = 'JWT' end diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 742b8b5..20fbc00 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -171,7 +171,6 @@ 279D63981AD07FFF0024E2BC /* Frameworks */, 279D63991AD07FFF0024E2BC /* Headers */, 279D639A1AD07FFF0024E2BC /* Resources */, - 842FB8EA008161B653B5AD81 /* Embed Pods Frameworks */, 6D3D4069FD3A7DC06168A6A2 /* Copy Pods Resources */, ); buildRules = ( @@ -210,6 +209,8 @@ 279D63931AD07FFF0024E2BC /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftMigration = 0700; + LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0620; ORGANIZATIONNAME = Cocode; TargetAttributes = { @@ -302,21 +303,6 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 842FB8EA008161B653B5AD81 /* Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWT/Pods-JWT-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; E68E26141F4DF11E3638A2F0 /* Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/JWT/Base64.swift b/JWT/Base64.swift index 9700992..b88162f 100644 --- a/JWT/Base64.swift +++ b/JWT/Base64.swift @@ -3,17 +3,17 @@ import Foundation /// URI Safe base64 encode func base64encode(input:NSData) -> String { - let data = input.base64EncodedDataWithOptions(NSDataBase64EncodingOptions(0)) + let data = input.base64EncodedDataWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String return string - .stringByReplacingOccurrencesOfString("+", withString: "-", options: NSStringCompareOptions(0), range: nil) - .stringByReplacingOccurrencesOfString("/", withString: "_", options: NSStringCompareOptions(0), range: nil) - .stringByReplacingOccurrencesOfString("=", withString: "", options: NSStringCompareOptions(0), range: nil) + .stringByReplacingOccurrencesOfString("+", withString: "-", options: NSStringCompareOptions(rawValue: 0), range: nil) + .stringByReplacingOccurrencesOfString("/", withString: "_", options: NSStringCompareOptions(rawValue: 0), range: nil) + .stringByReplacingOccurrencesOfString("=", withString: "", options: NSStringCompareOptions(rawValue: 0), range: nil) } /// URI Safe base64 decode func base64decode(input:String) -> NSData? { - let rem = count(input) % 4 + let rem = input.characters.count % 4 var ending = "" if rem > 0 { @@ -21,8 +21,8 @@ func base64decode(input:String) -> NSData? { ending = String(count: amount, repeatedValue: Character("=")) } - let base64 = input.stringByReplacingOccurrencesOfString("-", withString: "+", options: NSStringCompareOptions(0), range: nil) - .stringByReplacingOccurrencesOfString("_", withString: "/", options: NSStringCompareOptions(0), range: nil) + ending + let base64 = input.stringByReplacingOccurrencesOfString("-", withString: "+", options: NSStringCompareOptions(rawValue: 0), range: nil) + .stringByReplacingOccurrencesOfString("_", withString: "/", options: NSStringCompareOptions(rawValue: 0), range: nil) + ending - return NSData(base64EncodedString: base64, options: NSDataBase64DecodingOptions(0)) + return NSData(base64EncodedString: base64, options: NSDataBase64DecodingOptions(rawValue: 0)) } diff --git a/JWT/Claims.swift b/JWT/Claims.swift index 15964c4..6601ba0 100644 --- a/JWT/Claims.swift +++ b/JWT/Claims.swift @@ -1,16 +1,16 @@ import Foundation func validateClaims(payload:Payload, audience:String?, issuer:String?) -> InvalidToken? { - return validateIssuer(payload, issuer) ?? validateAudience(payload, audience) ?? - validateDate(payload, "exp", .OrderedAscending, .ExpiredSignature, "Expiration time claim (exp) must be an integer") ?? - validateDate(payload, "nbf", .OrderedDescending, .ImmatureSignature, "Not before claim (nbf) must be an integer") ?? - validateDate(payload, "iat", .OrderedDescending, .InvalidIssuedAt, "Issued at claim (iat) must be an integer") + return validateIssuer(payload, issuer: issuer) ?? validateAudience(payload, audience: audience) ?? + validateDate(payload, key: "exp", comparison: .OrderedAscending, failure: .ExpiredSignature, decodeError: "Expiration time claim (exp) must be an integer") ?? + validateDate(payload, key: "nbf", comparison: .OrderedDescending, failure: .ImmatureSignature, decodeError: "Not before claim (nbf) must be an integer") ?? + validateDate(payload, key: "iat", comparison: .OrderedDescending, failure: .InvalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") } func validateAudience(payload:Payload, audience:String?) -> InvalidToken? { if let audience = audience { if let aud = payload["aud"] as? [String] { - if !contains(aud, audience) { + if !aud.contains(audience) { return .InvalidAudience } } else if let aud = payload["aud"] as? String { @@ -45,7 +45,7 @@ func validateDate(payload:Payload, key:String, comparison:NSComparisonResult, fa if date.compare(NSDate()) == comparison { return failure } - } else if let timestamp:AnyObject = payload[key] { + } else if payload[key] != nil { return .DecodeError(decodeError) } diff --git a/JWT/Decode.swift b/JWT/Decode.swift index f44aa21..1a06e7a 100644 --- a/JWT/Decode.swift +++ b/JWT/Decode.swift @@ -2,7 +2,7 @@ import Foundation /// Failure reasons from decoding a JWT -public enum InvalidToken : Printable { +public enum InvalidToken : CustomStringConvertible { /// Decoding the JWT itself failed case DecodeError(String) @@ -60,7 +60,7 @@ public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audie switch load(jwt) { case let .Success(header, payload, signature, signatureInput): if verify { - if let failure = validateClaims(payload, audience, issuer) ?? verifySignature(algorithms, header, signatureInput, signature) { + if let failure = validateClaims(payload, audience: audience, issuer: issuer) ?? verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) { return .Failure(failure) } } @@ -73,7 +73,7 @@ public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audie /// Decode a JWT public func decode(jwt:String, algorithm:Algorithm, verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult { - return decode(jwt, [algorithm], verify: verify, audience: audience, issuer: issuer) + return decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer) } // MARK: Parsing a JWT @@ -99,7 +99,7 @@ func load(jwt:String) -> LoadResult { return .Failure(.DecodeError("Header is not correctly encoded as base64")) } - let header = NSJSONSerialization.JSONObjectWithData(headerData!, options: NSJSONReadingOptions(0), error: nil) as? Payload + let header = (try? NSJSONSerialization.JSONObjectWithData(headerData!, options: NSJSONReadingOptions(rawValue: 0))) as? Payload if header == nil { return .Failure(.DecodeError("Invalid header")) } @@ -109,7 +109,7 @@ func load(jwt:String) -> LoadResult { return .Failure(.DecodeError("Payload is not correctly encoded as base64")) } - let payload = NSJSONSerialization.JSONObjectWithData(payloadData!, options: NSJSONReadingOptions(0), error: nil) as? Payload + let payload = (try? NSJSONSerialization.JSONObjectWithData(payloadData!, options: NSJSONReadingOptions(rawValue: 0))) as? Payload if payload == nil { return .Failure(.DecodeError("Invalid payload")) } @@ -126,9 +126,9 @@ func load(jwt:String) -> LoadResult { func verifySignature(algorithms:[Algorithm], header:Payload, signingInput:String, signature:NSData) -> InvalidToken? { if let alg = header["alg"] as? String { - let matchingAlgorithms = filter(algorithms) { algorithm in algorithm.description == alg } - let results = map(matchingAlgorithms) { algorithm in algorithm.verify(signingInput, signature: signature) } - let successes = filter(results) { $0 } + let matchingAlgorithms = algorithms.filter { algorithm in algorithm.description == alg } + let results = matchingAlgorithms.map { algorithm in algorithm.verify(signingInput, signature: signature) } + let successes = results.filter { $0 } if successes.count > 0 { return nil } diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 9438118..65e7733 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -4,7 +4,7 @@ import CryptoSwift public typealias Payload = [String:AnyObject] /// The supported Algorithms -public enum Algorithm : Printable { +public enum Algorithm : CustomStringConvertible { /// No Algorithm, i-e, insecure case None @@ -19,7 +19,7 @@ public enum Algorithm : Printable { static func algorithm(name:String, key:String?) -> Algorithm? { if name == "none" { - if let key = key { + if key != nil { return nil // We don't allow nil when we configured a key } return Algorithm.None @@ -40,11 +40,11 @@ public enum Algorithm : Printable { switch self { case .None: return "none" - case .HS256(let key): + case .HS256: return "HS256" - case .HS384(let key): + case .HS384: return "HS384" - case .HS512(let key): + case .HS512: return "HS512" } } @@ -64,13 +64,13 @@ public enum Algorithm : Printable { return "" case .HS256(let key): - return signHS(key, .sha256) + return signHS(key, variant: .sha256) case .HS384(let key): - return signHS(key, .sha384) + return signHS(key, variant: .sha384) case .HS512(let key): - return signHS(key, .sha512) + return signHS(key, variant: .sha512) } } @@ -83,13 +83,13 @@ public enum Algorithm : Printable { // MARK: Encoding /*** Encode a payload - :param: payload The payload to sign - :param: algorithm The algorithm to sign the payload with - :returns: The JSON web token as a String + - parameter payload: The payload to sign + - parameter algorithm: The algorithm to sign the payload with + - returns: The JSON web token as a String */ public func encode(payload:Payload, algorithm:Algorithm) -> String { func encodeJSON(payload:Payload) -> String? { - if let data = NSJSONSerialization.dataWithJSONObject(payload, options: NSJSONWritingOptions(0), error: nil) { + if let data = try? NSJSONSerialization.dataWithJSONObject(payload, options: NSJSONWritingOptions(rawValue: 0)) { return base64encode(data) } @@ -176,5 +176,5 @@ public class PayloadBuilder { public func encode(algorithm:Algorithm, closure:(PayloadBuilder -> ())) -> String { let builder = PayloadBuilder() closure(builder) - return encode(builder.payload, algorithm) + return encode(builder.payload, algorithm: algorithm) } diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 584b7e7..7bec19a 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -4,7 +4,7 @@ import JWT class JWTEncodeTests : XCTestCase { func testEncodingJWT() { let payload = ["name": "Kyle"] as Payload - let jwt = JWT.encode(payload, .HS256("secret")) + let jwt = JWT.encode(payload, algorithm: .HS256("secret")) let fixture = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" XCTAssertEqual(jwt, fixture) } @@ -15,7 +15,7 @@ class JWTEncodeTests : XCTestCase { builder.issuer = "fuller.li" } - assertSuccess(JWT.decode(jwt, algorithm)) { payload in + assertSuccess(JWT.decode(jwt, algorithm: algorithm)) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } @@ -25,16 +25,16 @@ class JWTPayloadBuilder : XCTestCase { func testIssuer() { JWT.encode(.None) { builder in builder.issuer = "fuller.li" - XCTAssertEqual(builder.issuer!, "fuller.li") - XCTAssertEqual(builder["iss"] as! String, "fuller.li") + XCTAssertEqual(builder.issuer, "fuller.li") + XCTAssertEqual(builder["iss"] as? String, "fuller.li") } } func testAudience() { JWT.encode(.None) { builder in builder.audience = "cocoapods" - XCTAssertEqual(builder.audience!, "cocoapods") - XCTAssertEqual(builder["aud"] as! String, "cocoapods") + XCTAssertEqual(builder.audience, "cocoapods") + XCTAssertEqual(builder["aud"] as? String, "cocoapods") } } @@ -42,8 +42,8 @@ class JWTPayloadBuilder : XCTestCase { JWT.encode(.None) { builder in let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) builder.expiration = date - XCTAssertEqual(builder.expiration!, date) - XCTAssertEqual(builder["exp"] as! NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder.expiration, date) + XCTAssertEqual(builder["exp"] as? NSTimeInterval, date.timeIntervalSince1970) } } @@ -51,8 +51,8 @@ class JWTPayloadBuilder : XCTestCase { JWT.encode(.None) { builder in let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) builder.notBefore = date - XCTAssertEqual(builder.notBefore!, date) - XCTAssertEqual(builder["nbf"] as! NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder.notBefore, date) + XCTAssertEqual(builder["nbf"] as? NSTimeInterval, date.timeIntervalSince1970) } } @@ -60,15 +60,15 @@ class JWTPayloadBuilder : XCTestCase { JWT.encode(.None) { builder in let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) builder.issuedAt = date - XCTAssertEqual(builder.issuedAt!, date) - XCTAssertEqual(builder["iat"] as! NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder.issuedAt, date) + XCTAssertEqual(builder["iat"] as? NSTimeInterval, date.timeIntervalSince1970) } } func testCustomAttributes() { JWT.encode(.None) { builder in builder["user"] = "kyle" - XCTAssertEqual(builder["user"] as! String, "kyle") + XCTAssertEqual(builder["user"] as? String, "kyle") } } } @@ -76,58 +76,58 @@ class JWTPayloadBuilder : XCTestCase { class JWTDecodeTests : XCTestCase { func testDecodingValidJWT() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - let result = JWT.decode(jwt, .HS256("secret")) + let result = JWT.decode(jwt, algorithm: .HS256("secret")) assertSuccess(result) { payload in XCTAssertEqual(payload as NSDictionary, ["name": "Kyle"]) } } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - assertDecodeError(decode("a.b", .None), "Not enough segments") + assertDecodeError(decode("a.b", algorithm: .None), error: "Not enough segments") } // MARK: Disable verify func testDisablingVerify() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertSuccess(decode(jwt, .None, verify:false, issuer:"fuller.li")) + assertSuccess(decode(jwt, algorithm: .None, verify:false, issuer:"fuller.li")) } // MARK: Issuer claim func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(decode(jwt, .HS256("secret"), issuer:"fuller.li")) { payload in + assertSuccess(decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(decode(jwt, .HS256("secret"), issuer:"querykit.org")) + assertFailure(decode(jwt, algorithm: .HS256("secret"), issuer:"querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(decode(jwt, .HS256("secret"), issuer:"fuller.li")) + assertFailure(decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - assertFailure(decode(jwt, .HS256("secret"))) + assertFailure(decode(jwt, algorithm: .HS256("secret"))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - assertFailure(decode(jwt, .HS256("secret"))) + assertFailure(decode(jwt, algorithm: .HS256("secret"))) } func testUnexpiredClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - assertSuccess(decode(jwt, .HS256("secret"))) { payload in + assertSuccess(decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) } } @@ -136,27 +136,27 @@ class JWTDecodeTests : XCTestCase { func testNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - assertSuccess(decode(jwt, .HS256("secret"))) { payload in + assertSuccess(decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) } } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(decode(jwt, .HS256("secret")), "Not before claim (nbf) must be an integer") + assertDecodeError(decode(jwt, algorithm: .HS256("secret")), error: "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - assertFailure(decode(jwt, .HS256("secret"))) + assertFailure(decode(jwt, algorithm: .HS256("secret"))) } // MARK: Issued at claim func testIssuedAtClaimInThePast() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - assertSuccess(decode(jwt, .HS256("secret"))) { payload in + assertSuccess(decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) } } @@ -164,70 +164,70 @@ class JWTDecodeTests : XCTestCase { func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - assertFailure(decode(jwt, .HS256("secret"))) + assertFailure(decode(jwt, algorithm: .HS256("secret"))) } func testInvalidIssuedAtClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOlsxNzI4MTg4NDkxXX0.ND7QMWtLkXDXH38OaXM3SQgLo3Z5TNgF_pcfWHV_alQ" - assertDecodeError(decode(jwt, .HS256("secret")), "Issued at claim (iat) must be an integer") + assertDecodeError(decode(jwt, algorithm: .HS256("secret")), error: "Issued at claim (iat) must be an integer") } // MARK: Audience claims func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(decode(jwt, .HS256("secret"), audience:"maxine")) { payload in + assertSuccess(decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": ["maxine", "katie"]]) } } func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(decode(jwt, .HS256("secret"), audience:"kyle")) { payload in + assertSuccess(decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(decode(jwt, .HS256("secret"), audience:"maxine")) + assertFailure(decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(decode(jwt, .HS256("secret"), audience:"kyle")) + assertFailure(decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) } // MARK: Signature verification func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(decode(jwt, .None)) { payload in + assertSuccess(decode(jwt, algorithm:.None)) { payload in XCTAssertEqual(payload as NSDictionary, ["test": "ing"]) } } func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertFailure(decode(jwt, .HS256("secret"))) + assertFailure(decode(jwt, algorithm: .HS256("secret"))) } func testMatchesAnyAlgorithm() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." - assertFailure(decode(jwt, [.HS256("anothersecret"), .HS256("secret")])) + assertFailure(decode(jwt, algorithms: [.HS256("anothersecret"), .HS256("secret")])) } func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" - assertSuccess(decode(jwt, .HS384("secret"))) { payload in + assertSuccess(decode(jwt, algorithm: .HS384("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" - assertSuccess(decode(jwt, .HS512("secret"))) { payload in + assertSuccess(decode(jwt, algorithm: .HS512("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } @@ -249,7 +249,7 @@ func assertSuccess(result:DecodeResult, closure:(Payload -> ())? = nil) { func assertFailure(result:DecodeResult, closure:(InvalidToken -> ())? = nil) { switch result { - case .Success(let payload): + case .Success: XCTFail("Decoded when expecting a failure.") case .Failure(let failure): if let closure = closure { diff --git a/Podfile.lock b/Podfile.lock index f8320c5..c3d31ce 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,10 +1,10 @@ PODS: - - CryptoSwift (0.0.10) + - CryptoSwift (0.0.14) DEPENDENCIES: - - CryptoSwift (= 0.0.10) + - CryptoSwift (= 0.0.14) SPEC CHECKSUMS: - CryptoSwift: 3b886d001f50deb65623a8967d68f6b8bf8d9ba1 + CryptoSwift: 5a6b725e2ad65a789f5f435dd434d38eb2c40b46 -COCOAPODS: 0.36.4 +COCOAPODS: 0.39.0.beta.4 diff --git a/README.md b/README.md index fc2dbd0..1a1ed03 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ import JWT ### Encoding a claim ```swift -JWT.encode(["my": "payload"], .HS256("secret")) +JWT.encode(["my": "payload"], algorithm: .HS256("secret")) ``` #### Building a JWT with the builder pattern @@ -39,7 +39,7 @@ JWT.encode(.HS256("secret")) { builder in When decoding a JWT, you must supply one or more algorithms and keys. ```swift -let result = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", .HS256("secret")) +let result = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .HS256("secret")) switch result { case .Success(let payload): @@ -52,7 +52,7 @@ case .Failure(let failure): When the JWT may be signed with one out of many algorithms or keys: ```swift -let result = JWT.decode("eyJh...5w", [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) +let result = JWT.decode("eyJh...5w", algorithms: [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) ``` #### Supported claims From 924e5baa0eb0e6160e56a7dd8559f6f239cc0b18 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 18 Sep 2015 11:25:44 -0700 Subject: [PATCH 012/127] [Project] Update to Xcode 7 defaults --- JWT.xcodeproj/project.pbxproj | 7 ++++++- JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme | 13 ++++++++----- JWT/Info.plist | 2 +- JWTTests/Info.plist | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 20fbc00..6c89b7e 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -211,7 +211,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0620; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = Cocode; TargetAttributes = { 279D639B1AD07FFF0024E2BC = { @@ -386,6 +386,7 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -461,6 +462,7 @@ INFOPLIST_FILE = JWT/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -481,6 +483,7 @@ INFOPLIST_FILE = JWT/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -501,6 +504,7 @@ ); INFOPLIST_FILE = JWTTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -516,6 +520,7 @@ ); INFOPLIST_FILE = JWTTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme index 64d5bf3..6669b4d 100644 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:JWT.xcodeproj"> + + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.cocode.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/JWTTests/Info.plist b/JWTTests/Info.plist index d3de7c7..ba72822 100644 --- a/JWTTests/Info.plist +++ b/JWTTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.cocode.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName From d303591cc453faada459b860d1c99c161996c932 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 18 Sep 2015 11:38:16 -0700 Subject: [PATCH 013/127] Use ErrorType and throws for decoding --- JWT/Decode.swift | 23 ++++------- JWTTests/JWTTests.swift | 88 ++++++++++++++++++++--------------------- README.md | 14 +++---- 3 files changed, 55 insertions(+), 70 deletions(-) diff --git a/JWT/Decode.swift b/JWT/Decode.swift index 1a06e7a..c22a710 100644 --- a/JWT/Decode.swift +++ b/JWT/Decode.swift @@ -2,7 +2,7 @@ import Foundation /// Failure reasons from decoding a JWT -public enum InvalidToken : CustomStringConvertible { +public enum InvalidToken : CustomStringConvertible, ErrorType { /// Decoding the JWT itself failed case DecodeError(String) @@ -46,34 +46,25 @@ public enum InvalidToken : CustomStringConvertible { } -/// Result from decoding a JWT -public enum DecodeResult { - /// Decoding succeeded - case Success(Payload) - - /// Decoding failed, take a look at the invalid token reason - case Failure(InvalidToken) -} - /// Decode a JWT -public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult { +public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) throws -> Payload { switch load(jwt) { case let .Success(header, payload, signature, signatureInput): if verify { if let failure = validateClaims(payload, audience: audience, issuer: issuer) ?? verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) { - return .Failure(failure) + throw failure } } - return .Success(payload) + return payload case .Failure(let failure): - return .Failure(failure) + throw failure } } /// Decode a JWT -public func decode(jwt:String, algorithm:Algorithm, verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult { - return decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer) +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) } // MARK: Parsing a JWT diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 7bec19a..3e0edc6 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -15,7 +15,7 @@ class JWTEncodeTests : XCTestCase { builder.issuer = "fuller.li" } - assertSuccess(JWT.decode(jwt, algorithm: algorithm)) { payload in + assertSuccess(try JWT.decode(jwt, algorithm: algorithm)) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } @@ -76,58 +76,58 @@ class JWTPayloadBuilder : XCTestCase { class JWTDecodeTests : XCTestCase { func testDecodingValidJWT() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - let result = JWT.decode(jwt, algorithm: .HS256("secret")) - assertSuccess(result) { payload in + + assertSuccess(try JWT.decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["name": "Kyle"]) } } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - assertDecodeError(decode("a.b", algorithm: .None), error: "Not enough segments") + assertDecodeError(try decode("a.b", algorithm: .None), error: "Not enough segments") } // MARK: Disable verify func testDisablingVerify() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertSuccess(decode(jwt, algorithm: .None, verify:false, issuer:"fuller.li")) + assertSuccess(try decode(jwt, algorithm: .None, verify:false, issuer:"fuller.li")) } // MARK: Issuer claim func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) { payload in + assertSuccess(try decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(decode(jwt, algorithm: .HS256("secret"), issuer:"querykit.org")) + assertFailure(try decode(jwt, algorithm: .HS256("secret"), issuer:"querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) + assertFailure(try decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - assertFailure(decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .HS256("secret"))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - assertFailure(decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .HS256("secret"))) } func testUnexpiredClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - assertSuccess(decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) } } @@ -136,27 +136,27 @@ class JWTDecodeTests : XCTestCase { func testNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - assertSuccess(decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) } } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(decode(jwt, algorithm: .HS256("secret")), error: "Not before claim (nbf) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .HS256("secret")), error: "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - assertFailure(decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .HS256("secret"))) } // MARK: Issued at claim func testIssuedAtClaimInThePast() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - assertSuccess(decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) } } @@ -164,70 +164,70 @@ class JWTDecodeTests : XCTestCase { func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - assertFailure(decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .HS256("secret"))) } func testInvalidIssuedAtClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOlsxNzI4MTg4NDkxXX0.ND7QMWtLkXDXH38OaXM3SQgLo3Z5TNgF_pcfWHV_alQ" - assertDecodeError(decode(jwt, algorithm: .HS256("secret")), error: "Issued at claim (iat) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .HS256("secret")), error: "Issued at claim (iat) must be an integer") } // MARK: Audience claims func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) { payload in + assertSuccess(try decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": ["maxine", "katie"]]) } } func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) { payload in + assertSuccess(try decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) + assertFailure(try decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) + assertFailure(try decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) } // MARK: Signature verification func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(decode(jwt, algorithm:.None)) { payload in + assertSuccess(try decode(jwt, algorithm:.None)) { payload in XCTAssertEqual(payload as NSDictionary, ["test": "ing"]) } } func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertFailure(decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .HS256("secret"))) } func testMatchesAnyAlgorithm() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." - assertFailure(decode(jwt, algorithms: [.HS256("anothersecret"), .HS256("secret")])) + assertFailure(try decode(jwt, algorithms: [.HS256("anothersecret"), .HS256("secret")])) } func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" - assertSuccess(decode(jwt, algorithm: .HS384("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .HS384("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" - assertSuccess(decode(jwt, algorithm: .HS512("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .HS512("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } @@ -235,32 +235,28 @@ class JWTDecodeTests : XCTestCase { // MARK: Helpers -func assertSuccess(result:DecodeResult, closure:(Payload -> ())? = nil) { - switch result { - case .Success(let payload): - if let closure = closure { - closure(payload) - } - case .Failure(let failure): - XCTFail("Failed to decode while expecting success. \(failure)") - break +func assertSuccess(@autoclosure decoder:() throws -> Payload, closure:(Payload -> ())? = nil) { + do { + let payload = try decoder() + closure?(payload) + } catch { + XCTFail("Failed to decode while expecting success. \(error)") } } -func assertFailure(result:DecodeResult, closure:(InvalidToken -> ())? = nil) { - switch result { - case .Success: - XCTFail("Decoded when expecting a failure.") - case .Failure(let failure): - if let closure = closure { - closure(failure) - } - break +func assertFailure(@autoclosure decoder:() throws -> Payload, closure:(InvalidToken -> ())? = nil) { + do { + _ = try decoder() + XCTFail("Decoding succeeded, expected a failure.") + } catch let error as InvalidToken { + closure?(error) + } catch { + XCTFail("Unexpected error") } } -func assertDecodeError(result:DecodeResult, error:String) { - assertFailure(result) { failure in +func assertDecodeError(@autoclosure decoder:() throws -> Payload, error:String) { + assertFailure(try decoder()) { failure in switch failure { case .DecodeError(let decodeError): if decodeError != error { diff --git a/README.md b/README.md index 1a1ed03..61e156e 100644 --- a/README.md +++ b/README.md @@ -39,20 +39,18 @@ JWT.encode(.HS256("secret")) { builder in When decoding a JWT, you must supply one or more algorithms and keys. ```swift -let result = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .HS256("secret")) - -switch result { -case .Success(let payload): - print(payload) -case .Failure(let failure): - print("decoding failed \(failure)") +do { + let payload = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .HS256("secret")) + print(payload) +} catch { + print("Failed to decode JWT: \(error)") } ``` When the JWT may be signed with one out of many algorithms or keys: ```swift -let result = JWT.decode("eyJh...5w", algorithms: [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) +try JWT.decode("eyJh...5w", algorithms: [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) ``` #### Supported claims From 751bd8402b1a63142ea2c36c345782c81c822b5a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 18 Sep 2015 11:39:35 -0700 Subject: [PATCH 014/127] Release 1.4.0 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 8d74163..484f705 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.3.0' + spec.version = '1.4.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 9203e4929f64c3858e9b2feffd9984d687c60ff4 Mon Sep 17 00:00:00 2001 From: Curtis Herbert Date: Sat, 26 Sep 2015 10:50:48 -0400 Subject: [PATCH 015/127] Allow casting from String -> Double when checking timestamps Not all server-side JWT packages drop the quotes around returned values, which causes a decoding error to occur because `as? NSTimeInterval` will fail on strings. --- JWT/Claims.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JWT/Claims.swift b/JWT/Claims.swift index 6601ba0..fe7141b 100644 --- a/JWT/Claims.swift +++ b/JWT/Claims.swift @@ -40,7 +40,7 @@ func validateIssuer(payload:Payload, issuer:String?) -> InvalidToken? { } func validateDate(payload:Payload, key:String, comparison:NSComparisonResult, failure:InvalidToken, decodeError:String) -> InvalidToken? { - if let timestamp = payload[key] as? NSTimeInterval { + if let timestamp = payload[key] as? NSTimeInterval ?? payload[key]?.doubleValue as NSTimeInterval? { let date = NSDate(timeIntervalSince1970: timestamp) if date.compare(NSDate()) == comparison { return failure From c5bf6519e2f71f666658e0e037a14a69382ee435 Mon Sep 17 00:00:00 2001 From: Curtis Herbert Date: Sun, 27 Sep 2015 11:49:06 -0400 Subject: [PATCH 016/127] Added test to verify timestamps-as-strings pass verification --- JWTTests/JWTTests.swift | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 3e0edc6..9f8e4d4 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -131,6 +131,14 @@ class JWTDecodeTests : XCTestCase { XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) } } + + func testUnexpiredClaimString() { + // If this just started failing, hello 2024! + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" + assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + XCTAssertEqual(payload as NSDictionary, ["exp": "1728188491"]) + } + } // MARK: Not before claim @@ -140,6 +148,13 @@ class JWTDecodeTests : XCTestCase { XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) } } + + func testNotBeforeClaimString() { + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" + assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + XCTAssertEqual(payload as NSDictionary, ["nbf": "1428189720"]) + } + } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" @@ -160,6 +175,13 @@ class JWTDecodeTests : XCTestCase { XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) } } + + func testIssuedAtClaimInThePastString() { + let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" + assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + XCTAssertEqual(payload as NSDictionary, ["iat": "1428189720"]) + } + } func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! From 54b631d24bed3b9cfc5f8e3482e975d3b8b02f2a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 12 Oct 2015 09:23:28 -0700 Subject: [PATCH 017/127] Release 1.4.1 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 484f705..3d10bf2 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.4.0' + spec.version = '1.4.1' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 70352d8c8897166e0298966f8120d837f041f49c Mon Sep 17 00:00:00 2001 From: PyYoshi Date: Sat, 24 Oct 2015 13:14:54 +0900 Subject: [PATCH 018/127] Xcode automatic changes --- JWT.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 6c89b7e..aeee661 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -14,8 +14,8 @@ 279D63BB1AD0E3FA0024E2BC /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63BA1AD0E3FA0024E2BC /* Claims.swift */; }; 279D63BD1AD0ED750024E2BC /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63BC1AD0ED750024E2BC /* Decode.swift */; }; 279D63BF1AD0EDC00024E2BC /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63BE1AD0EDC00024E2BC /* Base64.swift */; }; - 885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540942F3614C41E3827F2013 /* Pods_JWT.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540942F3614C41E3827F2013 /* Pods_JWT.framework */; }; + EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ From 2844be81e307177d2c883e912006fb19f780fe7e Mon Sep 17 00:00:00 2001 From: PyYoshi Date: Sat, 24 Oct 2015 13:15:22 +0900 Subject: [PATCH 019/127] update to CryptoSwift 0.1.1 --- JSONWebToken.podspec | 3 +-- Podfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 3d10bf2..3274696 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -11,7 +11,6 @@ Pod::Spec.new do |spec| spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.requires_arc = true - spec.dependency 'CryptoSwift', '0.0.14' + spec.dependency 'CryptoSwift', '0.1.1' spec.module_name = 'JWT' end - diff --git a/Podfile.lock b/Podfile.lock index c3d31ce..a153187 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,10 +1,10 @@ PODS: - - CryptoSwift (0.0.14) + - CryptoSwift (0.1.1) DEPENDENCIES: - - CryptoSwift (= 0.0.14) + - CryptoSwift (= 0.1.1) SPEC CHECKSUMS: - CryptoSwift: 5a6b725e2ad65a789f5f435dd434d38eb2c40b46 + CryptoSwift: c11640d3d66107efc8333e4131a5173f072b1d61 -COCOAPODS: 0.39.0.beta.4 +COCOAPODS: 0.39.0 From bf37edc830bf0db36335a29dbf8c9e973bc4d229 Mon Sep 17 00:00:00 2001 From: PyYoshi Date: Sat, 24 Oct 2015 13:33:19 +0900 Subject: [PATCH 020/127] ignore error --- JWT/JWT.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 65e7733..0814630 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -55,7 +55,7 @@ public enum Algorithm : CustomStringConvertible { let keyData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let mac = Authenticator.HMAC(key: keyData.arrayOfBytes(), variant:variant) - let result = mac.authenticate(messageData.arrayOfBytes())! + let result = try! mac.authenticate(messageData.arrayOfBytes()) return base64encode(NSData.withBytes(result)) } From 3b0703857e879e98f30007b81348d78025574f24 Mon Sep 17 00:00:00 2001 From: PyYoshi Date: Sat, 24 Oct 2015 15:36:11 +0900 Subject: [PATCH 021/127] handle error --- JWT/JWT.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/JWT/JWT.swift b/JWT/JWT.swift index 0814630..bd6ba27 100644 --- a/JWT/JWT.swift +++ b/JWT/JWT.swift @@ -55,7 +55,12 @@ public enum Algorithm : CustomStringConvertible { let keyData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let mac = Authenticator.HMAC(key: keyData.arrayOfBytes(), variant:variant) - let result = try! mac.authenticate(messageData.arrayOfBytes()) + let result: [UInt8] + do { + result = try mac.authenticate(messageData.arrayOfBytes()) + } catch { + result = [] + } return base64encode(NSData.withBytes(result)) } From 25a04f70d5550d67acc1794acc220cd15c128b0f Mon Sep 17 00:00:00 2001 From: John Becker Date: Wed, 13 Jan 2016 10:15:53 -0500 Subject: [PATCH 022/127] Swift Package Manager Integration Added Package.swift with CryptoSwift dependency and moved code to Sources folder so the project can be used with Swift Package Manager. --- JSONWebToken.podspec | 6 ++--- JWT.xcodeproj/project.pbxproj | 42 ++++++++++++++++++++++------------- Package.swift | 8 +++++++ Podfile.lock | 6 ++--- README.md | 14 ++++++++++++ {JWT => Sources}/Base64.swift | 0 {JWT => Sources}/Claims.swift | 0 {JWT => Sources}/Decode.swift | 0 {JWT => Sources}/JWT.swift | 0 9 files changed, 54 insertions(+), 22 deletions(-) create mode 100644 Package.swift rename {JWT => Sources}/Base64.swift (100%) rename {JWT => Sources}/Claims.swift (100%) rename {JWT => Sources}/Decode.swift (100%) rename {JWT => Sources}/JWT.swift (100%) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 3274696..dea99ae 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,16 +1,16 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.4.1' + spec.version = '1.4.2' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } spec.social_media_url = 'http://twitter.com/kylefuller' spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git', :tag => "#{spec.version}" } - spec.source_files = 'JWT/*.swift' + spec.source_files = 'Sources/*.swift' spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.requires_arc = true - spec.dependency 'CryptoSwift', '0.1.1' + spec.dependency 'CryptoSwift', '0.2.2' spec.module_name = 'JWT' end diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index aeee661..aaa0756 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -10,10 +10,10 @@ 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; }; - 279D63B91AD0803F0024E2BC /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63B81AD0803F0024E2BC /* JWT.swift */; }; - 279D63BB1AD0E3FA0024E2BC /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63BA1AD0E3FA0024E2BC /* Claims.swift */; }; - 279D63BD1AD0ED750024E2BC /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63BC1AD0ED750024E2BC /* Decode.swift */; }; - 279D63BF1AD0EDC00024E2BC /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63BE1AD0EDC00024E2BC /* Base64.swift */; }; + 520A71171C469F010005C709 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; + 520A71181C469F010005C709 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; + 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; + 520A711A1C469F010005C709 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; 885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540942F3614C41E3827F2013 /* Pods_JWT.framework */; }; EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */; }; /* End PBXBuildFile section */ @@ -35,11 +35,12 @@ 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JWTTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 279D63AD1AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTTests.swift; sourceTree = ""; }; - 279D63B81AD0803F0024E2BC /* JWT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; - 279D63BA1AD0E3FA0024E2BC /* Claims.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Claims.swift; sourceTree = ""; }; - 279D63BC1AD0ED750024E2BC /* Decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decode.swift; sourceTree = ""; }; - 279D63BE1AD0EDC00024E2BC /* Base64.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base64.swift; sourceTree = ""; }; 3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWTTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests.debug.xcconfig"; sourceTree = ""; }; + 520A71131C469F010005C709 /* Base64.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base64.swift; sourceTree = ""; }; + 520A71141C469F010005C709 /* Claims.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Claims.swift; sourceTree = ""; }; + 520A71151C469F010005C709 /* Decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decode.swift; sourceTree = ""; }; + 520A71161C469F010005C709 /* JWT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; + 520A711B1C469F440005C709 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 540942F3614C41E3827F2013 /* Pods_JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWT.release.xcconfig"; path = "Pods/Target Support Files/Pods-JWT/Pods-JWT.release.xcconfig"; sourceTree = ""; }; 85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWTTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests.release.xcconfig"; sourceTree = ""; }; @@ -71,6 +72,8 @@ 279D63921AD07FFF0024E2BC = { isa = PBXGroup; children = ( + 520A711B1C469F440005C709 /* Package.swift */, + 520A71121C469F010005C709 /* Sources */, 279D639E1AD07FFF0024E2BC /* JWT */, 279D63AB1AD07FFF0024E2BC /* JWTTests */, 279D639D1AD07FFF0024E2BC /* Products */, @@ -94,10 +97,6 @@ isa = PBXGroup; children = ( 279D63A11AD07FFF0024E2BC /* JWT.h */, - 279D63B81AD0803F0024E2BC /* JWT.swift */, - 279D63BC1AD0ED750024E2BC /* Decode.swift */, - 279D63BE1AD0EDC00024E2BC /* Base64.swift */, - 279D63BA1AD0E3FA0024E2BC /* Claims.swift */, 279D639F1AD07FFF0024E2BC /* Supporting Files */, ); path = JWT; @@ -139,6 +138,17 @@ name = Pods; sourceTree = ""; }; + 520A71121C469F010005C709 /* Sources */ = { + isa = PBXGroup; + children = ( + 520A71131C469F010005C709 /* Base64.swift */, + 520A71141C469F010005C709 /* Claims.swift */, + 520A71151C469F010005C709 /* Decode.swift */, + 520A71161C469F010005C709 /* JWT.swift */, + ); + path = Sources; + sourceTree = ""; + }; AC8AE547FDAF3DD80EB4DB2F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -340,10 +350,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 279D63BF1AD0EDC00024E2BC /* Base64.swift in Sources */, - 279D63BB1AD0E3FA0024E2BC /* Claims.swift in Sources */, - 279D63BD1AD0ED750024E2BC /* Decode.swift in Sources */, - 279D63B91AD0803F0024E2BC /* JWT.swift in Sources */, + 520A71181C469F010005C709 /* Claims.swift in Sources */, + 520A711A1C469F010005C709 /* JWT.swift in Sources */, + 520A71191C469F010005C709 /* Decode.swift in Sources */, + 520A71171C469F010005C709 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..c0e4673 --- /dev/null +++ b/Package.swift @@ -0,0 +1,8 @@ +import PackageDescription + +let package = Package( + name: "JWT", + dependencies: [ + .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0,2,2).. Date: Mon, 8 Feb 2016 13:18:11 +0000 Subject: [PATCH 023/127] [podspec] Remove social URL --- JSONWebToken.podspec | 1 - 1 file changed, 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index dea99ae..8951093 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -5,7 +5,6 @@ Pod::Spec.new do |spec| spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } - spec.social_media_url = 'http://twitter.com/kylefuller' spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git', :tag => "#{spec.version}" } spec.source_files = 'Sources/*.swift' spec.ios.deployment_target = '8.0' From 042be77a27be670cf6d1287425094b7f49295220 Mon Sep 17 00:00:00 2001 From: Thaddeus Ternes Date: Mon, 8 Feb 2016 08:02:28 -0600 Subject: [PATCH 024/127] Add Carthage support --- .gitignore | 1 + .gitmodules | 3 + .travis.yml | 5 +- Cartfile | 1 + Cartfile.resolved | 1 + Carthage/Checkouts/CryptoSwift | 1 + JWT.xcodeproj/project.pbxproj | 221 ++++++++++++----------- JWT.xcworkspace/contents.xcworkspacedata | 10 - Podfile | 11 -- Podfile.lock | 10 - 10 files changed, 121 insertions(+), 143 deletions(-) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Cartfile create mode 100644 Cartfile.resolved create mode 160000 Carthage/Checkouts/CryptoSwift delete mode 100644 JWT.xcworkspace/contents.xcworkspacedata delete mode 100644 Podfile delete mode 100644 Podfile.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bce6af --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +xcuserdata diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..761522b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Carthage/Checkouts/CryptoSwift"] + path = Carthage/Checkouts/CryptoSwift + url = https://github.com/krzyzanowskim/CryptoSwift.git diff --git a/.travis.yml b/.travis.yml index 5eb95e8..f88a9f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,6 @@ before_install: - gem install xcpretty --no-document script: - set -o pipefail -- xcodebuild -workspace JWT.xcworkspace -scheme JWT test -sdk macosx | xcpretty -c -- pod lib lint +- git submodule update --init --recursive +- xcodebuild -project JWT.xcodeproj -scheme JWT test -sdk macosx | xcpretty -c +- pod lib lint --no-clean diff --git a/Cartfile b/Cartfile new file mode 100644 index 0000000..e3a2f44 --- /dev/null +++ b/Cartfile @@ -0,0 +1 @@ +github "krzyzanowskim/CryptoSwift" "0.2.2" diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 0000000..e3a2f44 --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "krzyzanowskim/CryptoSwift" "0.2.2" diff --git a/Carthage/Checkouts/CryptoSwift b/Carthage/Checkouts/CryptoSwift new file mode 160000 index 0000000..14e726d --- /dev/null +++ b/Carthage/Checkouts/CryptoSwift @@ -0,0 +1 @@ +Subproject commit 14e726db47efd6cbda0ff99b73dae2023ec354db diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index aaa0756..71f1e3b 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -14,8 +14,7 @@ 520A71181C469F010005C709 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; 520A711A1C469F010005C709 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; - 885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540942F3614C41E3827F2013 /* Pods_JWT.framework */; }; - EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */; }; + 66725DB61C59208400FC32F4 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -26,6 +25,48 @@ remoteGlobalIDString = 279D639B1AD07FFF0024E2BC; remoteInfo = JWT; }; + 66725DAA1C59202E00FC32F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 754BE45519693E190098E6F3; + remoteInfo = "CryptoSwift iOS"; + }; + 66725DAC1C59202E00FC32F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5596BDBB1BC8F220007E38D5; + remoteInfo = "CryptoSwift watchOS"; + }; + 66725DAE1C59202E00FC32F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 75D614BF1BD844F2001358B2; + remoteInfo = "CryptoSwift tvOS"; + }; + 66725DB01C59202E00FC32F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 75DF77721BC8EB59006E9520; + remoteInfo = "CryptoSwift OSX"; + }; + 66725DB21C59202E00FC32F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 754BE46019693E190098E6F3; + remoteInfo = CryptoSwiftTests; + }; + 66725DB41C59203B00FC32F4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 75DF77461BC8EB59006E9520; + remoteInfo = "CryptoSwift OSX"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -35,16 +76,13 @@ 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JWTTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 279D63AD1AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTTests.swift; sourceTree = ""; }; - 3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWTTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests.debug.xcconfig"; sourceTree = ""; }; 520A71131C469F010005C709 /* Base64.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base64.swift; sourceTree = ""; }; 520A71141C469F010005C709 /* Claims.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Claims.swift; sourceTree = ""; }; 520A71151C469F010005C709 /* Decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decode.swift; sourceTree = ""; }; 520A71161C469F010005C709 /* JWT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; 520A711B1C469F440005C709 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 540942F3614C41E3827F2013 /* Pods_JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWT.release.xcconfig"; path = "Pods/Target Support Files/Pods-JWT/Pods-JWT.release.xcconfig"; sourceTree = ""; }; - 85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWTTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests.release.xcconfig"; sourceTree = ""; }; - 8CDC721EB1EAFD72E8CCF46E /* Pods-JWT.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWT.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JWT/Pods-JWT.debug.xcconfig"; sourceTree = ""; }; + 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CryptoSwift.xcodeproj; path = Carthage/Checkouts/CryptoSwift/CryptoSwift.xcodeproj; sourceTree = ""; }; CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWTTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -53,7 +91,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */, + 66725DB61C59208400FC32F4 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -62,7 +100,6 @@ buildActionMask = 2147483647; files = ( 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */, - EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -72,12 +109,12 @@ 279D63921AD07FFF0024E2BC = { isa = PBXGroup; children = ( + 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */, 520A711B1C469F440005C709 /* Package.swift */, 520A71121C469F010005C709 /* Sources */, 279D639E1AD07FFF0024E2BC /* JWT */, 279D63AB1AD07FFF0024E2BC /* JWTTests */, 279D639D1AD07FFF0024E2BC /* Products */, - 378492BA2DE66F2F8E379F49 /* Pods */, AC8AE547FDAF3DD80EB4DB2F /* Frameworks */, ); indentWidth = 2; @@ -127,17 +164,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 378492BA2DE66F2F8E379F49 /* Pods */ = { - isa = PBXGroup; - children = ( - 8CDC721EB1EAFD72E8CCF46E /* Pods-JWT.debug.xcconfig */, - 56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */, - 3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */, - 85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; 520A71121C469F010005C709 /* Sources */ = { isa = PBXGroup; children = ( @@ -149,6 +175,18 @@ path = Sources; sourceTree = ""; }; + 66725DA31C59202E00FC32F4 /* Products */ = { + isa = PBXGroup; + children = ( + 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */, + 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */, + 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */, + 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */, + 66725DB31C59202E00FC32F4 /* CryptoSwiftTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; AC8AE547FDAF3DD80EB4DB2F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -176,16 +214,15 @@ isa = PBXNativeTarget; buildConfigurationList = 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT" */; buildPhases = ( - 4B9936F743EA727EA58353BD /* Check Pods Manifest.lock */, 279D63971AD07FFF0024E2BC /* Sources */, 279D63981AD07FFF0024E2BC /* Frameworks */, 279D63991AD07FFF0024E2BC /* Headers */, - 279D639A1AD07FFF0024E2BC /* Resources */, - 6D3D4069FD3A7DC06168A6A2 /* Copy Pods Resources */, + 66725DA11C591D9800FC32F4 /* Resources */, ); buildRules = ( ); dependencies = ( + 66725DB51C59203B00FC32F4 /* PBXTargetDependency */, ); name = JWT; productName = JWT; @@ -196,12 +233,9 @@ isa = PBXNativeTarget; buildConfigurationList = 279D63B51AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWTTests" */; buildPhases = ( - 7DCEFCF83F6CF372A33D5219 /* Check Pods Manifest.lock */, 279D63A31AD07FFF0024E2BC /* Sources */, 279D63A41AD07FFF0024E2BC /* Frameworks */, 279D63A51AD07FFF0024E2BC /* Resources */, - E68E26141F4DF11E3638A2F0 /* Embed Pods Frameworks */, - F7C4974401B24623F6907649 /* Copy Pods Resources */, ); buildRules = ( ); @@ -242,6 +276,12 @@ mainGroup = 279D63921AD07FFF0024E2BC; productRefGroup = 279D639D1AD07FFF0024E2BC /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 66725DA31C59202E00FC32F4 /* Products */; + ProjectRef = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + }, + ); projectRoot = ""; targets = ( 279D639B1AD07FFF0024E2BC /* JWT */, @@ -250,15 +290,53 @@ }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = CryptoSwift.framework; + remoteRef = 66725DAA1C59202E00FC32F4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = CryptoSwift.framework; + remoteRef = 66725DAC1C59202E00FC32F4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = CryptoSwift.framework; + remoteRef = 66725DAE1C59202E00FC32F4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = CryptoSwift.framework; + remoteRef = 66725DB01C59202E00FC32F4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 66725DB31C59202E00FC32F4 /* CryptoSwiftTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = CryptoSwiftTests.xctest; + remoteRef = 66725DB21C59202E00FC32F4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ - 279D639A1AD07FFF0024E2BC /* Resources */ = { + 279D63A51AD07FFF0024E2BC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 279D63A51AD07FFF0024E2BC /* Resources */ = { + 66725DA11C591D9800FC32F4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -267,84 +345,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 4B9936F743EA727EA58353BD /* Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Check Pods Manifest.lock"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; - 6D3D4069FD3A7DC06168A6A2 /* Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWT/Pods-JWT-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 7DCEFCF83F6CF372A33D5219 /* Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Check Pods Manifest.lock"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; - E68E26141F4DF11E3638A2F0 /* Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - F7C4974401B24623F6907649 /* Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 279D63971AD07FFF0024E2BC /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -373,6 +373,11 @@ target = 279D639B1AD07FFF0024E2BC /* JWT */; targetProxy = 279D63A91AD07FFF0024E2BC /* PBXContainerItemProxy */; }; + 66725DB51C59203B00FC32F4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CryptoSwift OSX"; + targetProxy = 66725DB41C59203B00FC32F4 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -460,7 +465,6 @@ }; 279D63B31AD07FFF0024E2BC /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 8CDC721EB1EAFD72E8CCF46E /* Pods-JWT.debug.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; @@ -481,7 +485,6 @@ }; 279D63B41AD07FFF0024E2BC /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; @@ -501,7 +504,6 @@ }; 279D63B61AD07FFF0024E2BC /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -521,7 +523,6 @@ }; 279D63B71AD07FFF0024E2BC /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( diff --git a/JWT.xcworkspace/contents.xcworkspacedata b/JWT.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 495e8bc..0000000 --- a/JWT.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/Podfile b/Podfile deleted file mode 100644 index 76e44d1..0000000 --- a/Podfile +++ /dev/null @@ -1,11 +0,0 @@ -platform :osx, '10.9' -use_frameworks! - -target 'JWT' do - podspec -end - -target 'JWTTests' do - podspec -end - diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index 268de89..0000000 --- a/Podfile.lock +++ /dev/null @@ -1,10 +0,0 @@ -PODS: - - CryptoSwift (0.2.2) - -DEPENDENCIES: - - CryptoSwift (= 0.2.2) - -SPEC CHECKSUMS: - CryptoSwift: d382228d6301c09474132417878a741c2a2e68cd - -COCOAPODS: 0.39.0 From bc1f1ef7440bc2873c7ed0ccce43884ac743e1f1 Mon Sep 17 00:00:00 2001 From: Max Fellmuth Date: Thu, 28 Jan 2016 16:29:17 +0100 Subject: [PATCH 025/127] [podspec] Add tvos deployment target --- .travis.yml | 5 +---- JSONWebToken.podspec | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f88a9f2..38c3309 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,5 @@ language: objective-c -osx_image: xcode7 -before_install: -- gem install cocoapods --no-document -- gem install xcpretty --no-document +osx_image: xcode7.2 script: - set -o pipefail - git submodule update --init --recursive diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 8951093..bdf8a74 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -9,6 +9,7 @@ Pod::Spec.new do |spec| spec.source_files = 'Sources/*.swift' spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' + spec.tvos.deployment_target = '9.0' spec.requires_arc = true spec.dependency 'CryptoSwift', '0.2.2' spec.module_name = 'JWT' From 5771d9847f0119d4151cdd197115401aa8c99aeb Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 16 Feb 2016 11:49:07 -0800 Subject: [PATCH 026/127] [travis] Lint podspec quickly --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 38c3309..52c505e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ script: - set -o pipefail - git submodule update --init --recursive - xcodebuild -project JWT.xcodeproj -scheme JWT test -sdk macosx | xcpretty -c -- pod lib lint --no-clean +- pod lib lint --quick From 6b6ca013f10c8ebd8f96cf61cfaa24f87474b86f Mon Sep 17 00:00:00 2001 From: Syo Ikeda Date: Fri, 19 Feb 2016 22:44:24 +0900 Subject: [PATCH 027/127] Add iOS, tvOS, watchOS targets --- .gitignore | 3 +- .travis.yml | 2 +- Cartfile | 2 +- Cartfile.resolved | 2 +- Carthage/Checkouts/CryptoSwift | 2 +- JWT.xcodeproj/project.pbxproj | 387 +++++++++++++++++- .../{JWT.xcscheme => JWT-OSX.xcscheme} | 12 +- .../xcshareddata/xcschemes/JWT-iOS.xcscheme | 80 ++++ .../xcshareddata/xcschemes/JWT-tvOS.xcscheme | 80 ++++ .../xcschemes/JWT-watchOS.xcscheme | 80 ++++ 10 files changed, 625 insertions(+), 25 deletions(-) rename JWT.xcodeproj/xcshareddata/xcschemes/{JWT.xcscheme => JWT-OSX.xcscheme} (94%) create mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme create mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme create mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme diff --git a/.gitignore b/.gitignore index 9bce6af..2295c9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -xcuserdata +xcuserdata/ +*.xccheckout diff --git a/.travis.yml b/.travis.yml index 52c505e..aa8257b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,5 @@ osx_image: xcode7.2 script: - set -o pipefail - git submodule update --init --recursive -- xcodebuild -project JWT.xcodeproj -scheme JWT test -sdk macosx | xcpretty -c +- xcodebuild -project JWT.xcodeproj -scheme JWT-OSX test -sdk macosx | xcpretty -c - pod lib lint --quick diff --git a/Cartfile b/Cartfile index e3a2f44..c22d502 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" "0.2.2" +github "krzyzanowskim/CryptoSwift" ~> 0.2.2 diff --git a/Cartfile.resolved b/Cartfile.resolved index e3a2f44..616e971 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" "0.2.2" +github "krzyzanowskim/CryptoSwift" "0.2.3" diff --git a/Carthage/Checkouts/CryptoSwift b/Carthage/Checkouts/CryptoSwift index 14e726d..2e011dd 160000 --- a/Carthage/Checkouts/CryptoSwift +++ b/Carthage/Checkouts/CryptoSwift @@ -1 +1 @@ -Subproject commit 14e726db47efd6cbda0ff99b73dae2023ec354db +Subproject commit 2e011dd834bfc82f0fd34b88495459f57e36aa38 diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 71f1e3b..e6b9000 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -15,6 +15,24 @@ 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; 520A711A1C469F010005C709 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; 66725DB61C59208400FC32F4 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */; }; + CD9B62171C7753D8005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; + CD9B62181C7753D8005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; + CD9B62191C7753D8005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; + CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; + CD9B621E1C7753D8005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CD9B62291C7753EC005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; + CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; + CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; + CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; + CD9B62301C7753EC005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; + CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; + CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; + CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; + CD9B62421C7753FB005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CD9B62891C7758BB005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; + CD9B628E1C7758E5005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */; }; + CD9B62911C775900005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -67,6 +85,27 @@ remoteGlobalIDString = 75DF77461BC8EB59006E9520; remoteInfo = "CryptoSwift OSX"; }; + CD9B628A1C7758CA005D4844 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 754BE45419693E190098E6F3; + remoteInfo = "CryptoSwift iOS"; + }; + CD9B628C1C7758DA005D4844 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 75D614921BD844F2001358B2; + remoteInfo = "CryptoSwift tvOS"; + }; + CD9B628F1C7758FB005D4844 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 5596BDBA1BC8F220007E38D5; + remoteInfo = "CryptoSwift watchOS"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -83,6 +122,9 @@ 520A711B1C469F440005C709 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 540942F3614C41E3827F2013 /* Pods_JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CryptoSwift.xcodeproj; path = Carthage/Checkouts/CryptoSwift/CryptoSwift.xcodeproj; sourceTree = ""; }; + CD9B62231C7753D8005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CD9B62351C7753EC005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CD9B62471C7753FB005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWTTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -103,6 +145,30 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + CD9B621B1C7753D8005D4844 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B62891C7758BB005D4844 /* CryptoSwift.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B622D1C7753EC005D4844 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B628E1C7758E5005D4844 /* CryptoSwift.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B623F1C7753FB005D4844 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B62911C775900005D4844 /* CryptoSwift.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -126,6 +192,9 @@ children = ( 279D639C1AD07FFF0024E2BC /* JWT.framework */, 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */, + CD9B62231C7753D8005D4844 /* JWT.framework */, + CD9B62351C7753EC005D4844 /* JWT.framework */, + CD9B62471C7753FB005D4844 /* JWT.framework */, ); name = Products; sourceTree = ""; @@ -180,8 +249,8 @@ children = ( 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */, 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */, - 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */, 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */, + 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */, 66725DB31C59202E00FC32F4 /* CryptoSwiftTests.xctest */, ); name = Products; @@ -207,12 +276,36 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + CD9B621D1C7753D8005D4844 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B621E1C7753D8005D4844 /* JWT.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B622F1C7753EC005D4844 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B62301C7753EC005D4844 /* JWT.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B62411C7753FB005D4844 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B62421C7753FB005D4844 /* JWT.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 279D639B1AD07FFF0024E2BC /* JWT */ = { + 279D639B1AD07FFF0024E2BC /* JWT-OSX */ = { isa = PBXNativeTarget; - buildConfigurationList = 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT" */; + buildConfigurationList = 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT-OSX" */; buildPhases = ( 279D63971AD07FFF0024E2BC /* Sources */, 279D63981AD07FFF0024E2BC /* Frameworks */, @@ -224,7 +317,7 @@ dependencies = ( 66725DB51C59203B00FC32F4 /* PBXTargetDependency */, ); - name = JWT; + name = "JWT-OSX"; productName = JWT; productReference = 279D639C1AD07FFF0024E2BC /* JWT.framework */; productType = "com.apple.product-type.framework"; @@ -247,6 +340,63 @@ productReference = 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + CD9B62131C7753D8005D4844 /* JWT-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD9B62201C7753D8005D4844 /* Build configuration list for PBXNativeTarget "JWT-iOS" */; + buildPhases = ( + CD9B62161C7753D8005D4844 /* Sources */, + CD9B621B1C7753D8005D4844 /* Frameworks */, + CD9B621D1C7753D8005D4844 /* Headers */, + CD9B621F1C7753D8005D4844 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + CD9B628B1C7758CA005D4844 /* PBXTargetDependency */, + ); + name = "JWT-iOS"; + productName = JWT; + productReference = CD9B62231C7753D8005D4844 /* JWT.framework */; + productType = "com.apple.product-type.framework"; + }; + CD9B62251C7753EC005D4844 /* JWT-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD9B62321C7753EC005D4844 /* Build configuration list for PBXNativeTarget "JWT-tvOS" */; + buildPhases = ( + CD9B62281C7753EC005D4844 /* Sources */, + CD9B622D1C7753EC005D4844 /* Frameworks */, + CD9B622F1C7753EC005D4844 /* Headers */, + CD9B62311C7753EC005D4844 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + CD9B628D1C7758DA005D4844 /* PBXTargetDependency */, + ); + name = "JWT-tvOS"; + productName = JWT; + productReference = CD9B62351C7753EC005D4844 /* JWT.framework */; + productType = "com.apple.product-type.framework"; + }; + CD9B62371C7753FB005D4844 /* JWT-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD9B62441C7753FB005D4844 /* Build configuration list for PBXNativeTarget "JWT-watchOS" */; + buildPhases = ( + CD9B623A1C7753FB005D4844 /* Sources */, + CD9B623F1C7753FB005D4844 /* Frameworks */, + CD9B62411C7753FB005D4844 /* Headers */, + CD9B62431C7753FB005D4844 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + CD9B62901C7758FB005D4844 /* PBXTargetDependency */, + ); + name = "JWT-watchOS"; + productName = JWT; + productReference = CD9B62471C7753FB005D4844 /* JWT.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -284,7 +434,10 @@ ); projectRoot = ""; targets = ( - 279D639B1AD07FFF0024E2BC /* JWT */, + 279D639B1AD07FFF0024E2BC /* JWT-OSX */, + CD9B62131C7753D8005D4844 /* JWT-iOS */, + CD9B62251C7753EC005D4844 /* JWT-tvOS */, + CD9B62371C7753FB005D4844 /* JWT-watchOS */, 279D63A61AD07FFF0024E2BC /* JWTTests */, ); }; @@ -343,6 +496,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + CD9B621F1C7753D8005D4844 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B62311C7753EC005D4844 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B62431C7753FB005D4844 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -365,12 +539,45 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + CD9B62161C7753D8005D4844 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, + CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, + CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, + CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B62281C7753EC005D4844 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, + CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, + CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, + CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD9B623A1C7753FB005D4844 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, + CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, + CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, + CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 279D63AA1AD07FFF0024E2BC /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 279D639B1AD07FFF0024E2BC /* JWT */; + target = 279D639B1AD07FFF0024E2BC /* JWT-OSX */; targetProxy = 279D63A91AD07FFF0024E2BC /* PBXContainerItemProxy */; }; 66725DB51C59203B00FC32F4 /* PBXTargetDependency */ = { @@ -378,6 +585,21 @@ name = "CryptoSwift OSX"; targetProxy = 66725DB41C59203B00FC32F4 /* PBXContainerItemProxy */; }; + CD9B628B1C7758CA005D4844 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CryptoSwift iOS"; + targetProxy = CD9B628A1C7758CA005D4844 /* PBXContainerItemProxy */; + }; + CD9B628D1C7758DA005D4844 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CryptoSwift tvOS"; + targetProxy = CD9B628C1C7758DA005D4844 /* PBXContainerItemProxy */; + }; + CD9B62901C7758FB005D4844 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CryptoSwift watchOS"; + targetProxy = CD9B628F1C7758FB005D4844 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -419,6 +641,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; VERSIONING_SYSTEM = "apple-generic"; @@ -457,6 +680,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -466,7 +690,6 @@ 279D63B31AD07FFF0024E2BC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -474,19 +697,16 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 279D63B41AD07FFF0024E2BC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -494,10 +714,9 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; @@ -536,6 +755,119 @@ }; name = Release; }; + CD9B62211C7753D8005D4844 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = JWT/Info.plist; + INSTALL_PATH = "@rpath"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + CD9B62221C7753D8005D4844 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = JWT/Info.plist; + INSTALL_PATH = "@rpath"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + CD9B62331C7753EC005D4844 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = JWT/Info.plist; + INSTALL_PATH = "@rpath"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + }; + name = Debug; + }; + CD9B62341C7753EC005D4844 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = JWT/Info.plist; + INSTALL_PATH = "@rpath"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + CD9B62451C7753FB005D4844 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = JWT/Info.plist; + INSTALL_PATH = "@rpath"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + CD9B62461C7753FB005D4844 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = JWT/Info.plist; + INSTALL_PATH = "@rpath"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -548,7 +880,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT" */ = { + 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT-OSX" */ = { isa = XCConfigurationList; buildConfigurations = ( 279D63B31AD07FFF0024E2BC /* Debug */, @@ -566,6 +898,33 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + CD9B62201C7753D8005D4844 /* Build configuration list for PBXNativeTarget "JWT-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD9B62211C7753D8005D4844 /* Debug */, + CD9B62221C7753D8005D4844 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CD9B62321C7753EC005D4844 /* Build configuration list for PBXNativeTarget "JWT-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD9B62331C7753EC005D4844 /* Debug */, + CD9B62341C7753EC005D4844 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CD9B62441C7753FB005D4844 /* Build configuration list for PBXNativeTarget "JWT-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD9B62451C7753FB005D4844 /* Debug */, + CD9B62461C7753FB005D4844 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 279D63931AD07FFF0024E2BC /* Project object */; diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme similarity index 94% rename from JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme rename to JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme index 6669b4d..1d4884e 100644 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT.xcscheme +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme @@ -16,16 +16,16 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "279D639B1AD07FFF0024E2BC" BuildableName = "JWT.framework" - BlueprintName = "JWT" + BlueprintName = "JWT-OSX" ReferencedContainer = "container:JWT.xcodeproj"> + buildForAnalyzing = "NO"> @@ -80,7 +80,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "279D639B1AD07FFF0024E2BC" BuildableName = "JWT.framework" - BlueprintName = "JWT" + BlueprintName = "JWT-OSX" ReferencedContainer = "container:JWT.xcodeproj"> @@ -98,7 +98,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "279D639B1AD07FFF0024E2BC" BuildableName = "JWT.framework" - BlueprintName = "JWT" + BlueprintName = "JWT-OSX" ReferencedContainer = "container:JWT.xcodeproj"> diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme new file mode 100644 index 0000000..d3cea84 --- /dev/null +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme new file mode 100644 index 0000000..845425c --- /dev/null +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme new file mode 100644 index 0000000..8cab020 --- /dev/null +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 5c444a4dced1ea104b5885ca01189ac3e4176c5f Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 29 Mar 2016 17:48:01 +0200 Subject: [PATCH 028/127] [README] Remove mention of Swift Package Manager --- README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/README.md b/README.md index df8edaa..61e156e 100644 --- a/README.md +++ b/README.md @@ -12,20 +12,6 @@ Swift implementation of [JSON Web Token](https://tools.ietf.org/html/draft-ietf- pod 'JSONWebToken' ``` -[Swift Package Manager](https://swift.org/package-manager/) installation is also available with the following dependency: - -```swift -import PackageDescription - -let package = Package( - name: "AwesomeProject", - dependencies: [ - .Package(url: "https://github.com/kylef/JSONWebToken.swift", versions: Version(1,4,2).. Date: Tue, 29 Mar 2016 17:49:51 +0200 Subject: [PATCH 029/127] Release 1.4.3 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index bdf8a74..d561e58 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.4.2' + spec.version = '1.4.3' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 16000729afcb191881d2e05e537dbd96be02a228 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 31 Mar 2016 10:40:27 +0200 Subject: [PATCH 030/127] [podspec] Depend on CryptoSwift ~> 0.2.2 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index d561e58..15a5422 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -11,6 +11,6 @@ Pod::Spec.new do |spec| spec.osx.deployment_target = '10.9' spec.tvos.deployment_target = '9.0' spec.requires_arc = true - spec.dependency 'CryptoSwift', '0.2.2' + spec.dependency 'CryptoSwift', '~> 0.2.2' spec.module_name = 'JWT' end From 52c697855c5beb9ba92d1b255986b2c1001cabf5 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 15 May 2016 19:39:26 -0700 Subject: [PATCH 031/127] Update to CryptoSwift 0.4 --- .travis.yml | 2 +- Cartfile | 2 +- Cartfile.resolved | 2 +- Carthage/Checkouts/CryptoSwift | 2 +- JSONWebToken.podspec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index aa8257b..e933fca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.2 +osx_image: xcode7.3 script: - set -o pipefail - git submodule update --init --recursive diff --git a/Cartfile b/Cartfile index c22d502..e002d56 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" ~> 0.2.2 +github "krzyzanowskim/CryptoSwift" ~> 0.4.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index 616e971..3041c75 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" "0.2.3" +github "krzyzanowskim/CryptoSwift" "0.4.0" diff --git a/Carthage/Checkouts/CryptoSwift b/Carthage/Checkouts/CryptoSwift index 2e011dd..3a0c315 160000 --- a/Carthage/Checkouts/CryptoSwift +++ b/Carthage/Checkouts/CryptoSwift @@ -1 +1 @@ -Subproject commit 2e011dd834bfc82f0fd34b88495459f57e36aa38 +Subproject commit 3a0c3153717070a42971c30cd73d67f6f832f4bc diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 15a5422..9c9e47d 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -11,6 +11,6 @@ Pod::Spec.new do |spec| spec.osx.deployment_target = '10.9' spec.tvos.deployment_target = '9.0' spec.requires_arc = true - spec.dependency 'CryptoSwift', '~> 0.2.2' + spec.dependency 'CryptoSwift', '~> 0.4.0' spec.module_name = 'JWT' end From 6a1bc821d484c1c62bcfb7027b30084c7036aaf1 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 15 May 2016 19:55:55 -0700 Subject: [PATCH 032/127] Release 0.5.0 --- CHANGELOG.md | 5 +++++ JSONWebToken.podspec | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f7deb66 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# JSON Web Token Changelog +## 0.5.0 + +This release updates the dependency on CryptoSwift to ~> 0.4.0 which adds +support for Swift 2.2. diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 9c9e47d..53b720c 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.4.3' + spec.version = '1.5.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 65ab050c7bc1073a6d634d3105a575efb5edc70a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 13 Sep 2016 10:29:08 +0100 Subject: [PATCH 033/127] Update CryptoSwift to 0.6.0 --- Cartfile | 2 +- Cartfile.resolved | 2 +- Carthage/Checkouts/CryptoSwift | 2 +- JSONWebToken.podspec | 2 +- Package.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cartfile b/Cartfile index e002d56..b5f890d 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" ~> 0.4.0 +github "krzyzanowskim/CryptoSwift" ~> 0.6.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index 3041c75..5909a7d 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" "0.4.0" +github "krzyzanowskim/CryptoSwift" "0.6.0" diff --git a/Carthage/Checkouts/CryptoSwift b/Carthage/Checkouts/CryptoSwift index 3a0c315..fd7bd48 160000 --- a/Carthage/Checkouts/CryptoSwift +++ b/Carthage/Checkouts/CryptoSwift @@ -1 +1 @@ -Subproject commit 3a0c3153717070a42971c30cd73d67f6f832f4bc +Subproject commit fd7bd483a67ab19351db38248ff82a26d8df7cbe diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 53b720c..244b162 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -11,6 +11,6 @@ Pod::Spec.new do |spec| spec.osx.deployment_target = '10.9' spec.tvos.deployment_target = '9.0' spec.requires_arc = true - spec.dependency 'CryptoSwift', '~> 0.4.0' + spec.dependency 'CryptoSwift', '~> 0.6.0' spec.module_name = 'JWT' end diff --git a/Package.swift b/Package.swift index c0e4673..cd938aa 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,6 @@ import PackageDescription let package = Package( name: "JWT", dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0,2,2).. Date: Tue, 13 Sep 2016 10:48:18 +0100 Subject: [PATCH 034/127] Support Swift 3.0 --- .travis.yml | 2 +- JWT.xcodeproj/project.pbxproj | 104 ++++------------------------------ JWTTests/JWTTests.swift | 90 ++++++++++++++--------------- README.md | 16 +++--- Sources/Base64.swift | 22 +++---- Sources/Claims.swift | 32 +++++------ Sources/Decode.swift | 70 +++++++++++------------ Sources/JWT.swift | 98 ++++++++++++++++---------------- 8 files changed, 176 insertions(+), 258 deletions(-) diff --git a/.travis.yml b/.travis.yml index e933fca..37e3d17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 script: - set -o pipefail - git submodule update --init --recursive diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index e6b9000..86147ea 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 2734C6A81D88001F00BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; + 2734C6A91D88002900BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; + 2734C6AA1D88003000BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; }; @@ -14,7 +17,6 @@ 520A71181C469F010005C709 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; 520A711A1C469F010005C709 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; - 66725DB61C59208400FC32F4 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */; }; CD9B62171C7753D8005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; CD9B62181C7753D8005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; CD9B62191C7753D8005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; @@ -31,8 +33,6 @@ CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; CD9B62421C7753FB005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; CD9B62891C7758BB005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; - CD9B628E1C7758E5005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */; }; - CD9B62911C775900005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -50,27 +50,6 @@ remoteGlobalIDString = 754BE45519693E190098E6F3; remoteInfo = "CryptoSwift iOS"; }; - 66725DAC1C59202E00FC32F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 5596BDBB1BC8F220007E38D5; - remoteInfo = "CryptoSwift watchOS"; - }; - 66725DAE1C59202E00FC32F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 75D614BF1BD844F2001358B2; - remoteInfo = "CryptoSwift tvOS"; - }; - 66725DB01C59202E00FC32F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 75DF77721BC8EB59006E9520; - remoteInfo = "CryptoSwift OSX"; - }; 66725DB21C59202E00FC32F4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; @@ -78,13 +57,6 @@ remoteGlobalIDString = 754BE46019693E190098E6F3; remoteInfo = CryptoSwiftTests; }; - 66725DB41C59203B00FC32F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 75DF77461BC8EB59006E9520; - remoteInfo = "CryptoSwift OSX"; - }; CD9B628A1C7758CA005D4844 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; @@ -92,20 +64,6 @@ remoteGlobalIDString = 754BE45419693E190098E6F3; remoteInfo = "CryptoSwift iOS"; }; - CD9B628C1C7758DA005D4844 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 75D614921BD844F2001358B2; - remoteInfo = "CryptoSwift tvOS"; - }; - CD9B628F1C7758FB005D4844 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 5596BDBA1BC8F220007E38D5; - remoteInfo = "CryptoSwift watchOS"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -133,7 +91,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 66725DB61C59208400FC32F4 /* CryptoSwift.framework in Frameworks */, + 2734C6A81D88001F00BFF9F1 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -157,7 +115,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CD9B628E1C7758E5005D4844 /* CryptoSwift.framework in Frameworks */, + 2734C6A91D88002900BFF9F1 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -165,7 +123,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CD9B62911C775900005D4844 /* CryptoSwift.framework in Frameworks */, + 2734C6AA1D88003000BFF9F1 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -248,10 +206,7 @@ isa = PBXGroup; children = ( 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */, - 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */, - 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */, - 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */, - 66725DB31C59202E00FC32F4 /* CryptoSwiftTests.xctest */, + 66725DB31C59202E00FC32F4 /* Tests.xctest */, ); name = Products; sourceTree = ""; @@ -315,7 +270,6 @@ buildRules = ( ); dependencies = ( - 66725DB51C59203B00FC32F4 /* PBXTargetDependency */, ); name = "JWT-OSX"; productName = JWT; @@ -371,7 +325,6 @@ buildRules = ( ); dependencies = ( - CD9B628D1C7758DA005D4844 /* PBXTargetDependency */, ); name = "JWT-tvOS"; productName = JWT; @@ -390,7 +343,6 @@ buildRules = ( ); dependencies = ( - CD9B62901C7758FB005D4844 /* PBXTargetDependency */, ); name = "JWT-watchOS"; productName = JWT; @@ -451,31 +403,10 @@ remoteRef = 66725DAA1C59202E00FC32F4 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 66725DAD1C59202E00FC32F4 /* CryptoSwift.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CryptoSwift.framework; - remoteRef = 66725DAC1C59202E00FC32F4 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 66725DAF1C59202E00FC32F4 /* CryptoSwift.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CryptoSwift.framework; - remoteRef = 66725DAE1C59202E00FC32F4 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 66725DB11C59202E00FC32F4 /* CryptoSwift.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CryptoSwift.framework; - remoteRef = 66725DB01C59202E00FC32F4 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 66725DB31C59202E00FC32F4 /* CryptoSwiftTests.xctest */ = { + 66725DB31C59202E00FC32F4 /* Tests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; - path = CryptoSwiftTests.xctest; + path = Tests.xctest; remoteRef = 66725DB21C59202E00FC32F4 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -580,26 +511,11 @@ target = 279D639B1AD07FFF0024E2BC /* JWT-OSX */; targetProxy = 279D63A91AD07FFF0024E2BC /* PBXContainerItemProxy */; }; - 66725DB51C59203B00FC32F4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "CryptoSwift OSX"; - targetProxy = 66725DB41C59203B00FC32F4 /* PBXContainerItemProxy */; - }; CD9B628B1C7758CA005D4844 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "CryptoSwift iOS"; targetProxy = CD9B628A1C7758CA005D4844 /* PBXContainerItemProxy */; }; - CD9B628D1C7758DA005D4844 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "CryptoSwift tvOS"; - targetProxy = CD9B628C1C7758DA005D4844 /* PBXContainerItemProxy */; - }; - CD9B62901C7758FB005D4844 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "CryptoSwift watchOS"; - targetProxy = CD9B628F1C7758FB005D4844 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -644,6 +560,7 @@ PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -682,6 +599,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 9f8e4d4..4eacf56 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -4,13 +4,13 @@ import JWT class JWTEncodeTests : XCTestCase { func testEncodingJWT() { let payload = ["name": "Kyle"] as Payload - let jwt = JWT.encode(payload, algorithm: .HS256("secret")) + let jwt = JWT.encode(payload, algorithm: .hs256("secret")) let fixture = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" XCTAssertEqual(jwt, fixture) } func testEncodingWithBuilder() { - let algorithm = Algorithm.HS256("secret") + let algorithm = Algorithm.hs256("secret") let jwt = JWT.encode(algorithm) { builder in builder.issuer = "fuller.li" } @@ -23,7 +23,7 @@ class JWTEncodeTests : XCTestCase { class JWTPayloadBuilder : XCTestCase { func testIssuer() { - JWT.encode(.None) { builder in + JWT.encode(.none) { builder in builder.issuer = "fuller.li" XCTAssertEqual(builder.issuer, "fuller.li") XCTAssertEqual(builder["iss"] as? String, "fuller.li") @@ -31,7 +31,7 @@ class JWTPayloadBuilder : XCTestCase { } func testAudience() { - JWT.encode(.None) { builder in + JWT.encode(.none) { builder in builder.audience = "cocoapods" XCTAssertEqual(builder.audience, "cocoapods") XCTAssertEqual(builder["aud"] as? String, "cocoapods") @@ -39,34 +39,34 @@ class JWTPayloadBuilder : XCTestCase { } func testExpiration() { - JWT.encode(.None) { builder in - let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) + JWT.encode(.none) { builder in + let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) builder.expiration = date XCTAssertEqual(builder.expiration, date) - XCTAssertEqual(builder["exp"] as? NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder["exp"] as? TimeInterval, date.timeIntervalSince1970) } } func testNotBefore() { - JWT.encode(.None) { builder in - let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) + JWT.encode(.none) { builder in + let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) builder.notBefore = date XCTAssertEqual(builder.notBefore, date) - XCTAssertEqual(builder["nbf"] as? NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder["nbf"] as? TimeInterval, date.timeIntervalSince1970) } } func testIssuedAt() { - JWT.encode(.None) { builder in - let date = NSDate(timeIntervalSince1970: NSDate().timeIntervalSince1970) + JWT.encode(.none) { builder in + let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) builder.issuedAt = date XCTAssertEqual(builder.issuedAt, date) - XCTAssertEqual(builder["iat"] as? NSTimeInterval, date.timeIntervalSince1970) + XCTAssertEqual(builder["iat"] as? TimeInterval, date.timeIntervalSince1970) } } func testCustomAttributes() { - JWT.encode(.None) { builder in + JWT.encode(.none) { builder in builder["user"] = "kyle" XCTAssertEqual(builder["user"] as? String, "kyle") } @@ -77,57 +77,57 @@ class JWTDecodeTests : XCTestCase { func testDecodingValidJWT() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - assertSuccess(try JWT.decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try JWT.decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["name": "Kyle"]) } } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - assertDecodeError(try decode("a.b", algorithm: .None), error: "Not enough segments") + assertDecodeError(try decode("a.b", algorithm: .none), error: "Not enough segments") } // MARK: Disable verify func testDisablingVerify() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertSuccess(try decode(jwt, algorithm: .None, verify:false, issuer:"fuller.li")) + assertSuccess(try decode(jwt, algorithm: .none, verify:false, issuer:"fuller.li")) } // MARK: Issuer claim func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"), issuer:"fuller.li")) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(try decode(jwt, algorithm: .HS256("secret"), issuer:"querykit.org")) + assertFailure(try decode(jwt, algorithm: .hs256("secret"), issuer:"querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .HS256("secret"), issuer:"fuller.li")) + assertFailure(try decode(jwt, algorithm: .hs256("secret"), issuer:"fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - assertFailure(try decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret"))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - assertFailure(try decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret"))) } func testUnexpiredClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) } } @@ -135,7 +135,7 @@ class JWTDecodeTests : XCTestCase { func testUnexpiredClaimString() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": "1728188491"]) } } @@ -144,41 +144,41 @@ class JWTDecodeTests : XCTestCase { func testNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) } } func testNotBeforeClaimString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": "1428189720"]) } } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(try decode(jwt, algorithm: .HS256("secret")), error: "Not before claim (nbf) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .hs256("secret")), error: "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - assertFailure(try decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret"))) } // MARK: Issued at claim func testIssuedAtClaimInThePast() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) } } func testIssuedAtClaimInThePastString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": "1428189720"]) } } @@ -186,70 +186,70 @@ class JWTDecodeTests : XCTestCase { func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - assertFailure(try decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret"))) } func testInvalidIssuedAtClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOlsxNzI4MTg4NDkxXX0.ND7QMWtLkXDXH38OaXM3SQgLo3Z5TNgF_pcfWHV_alQ" - assertDecodeError(try decode(jwt, algorithm: .HS256("secret")), error: "Issued at claim (iat) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .hs256("secret")), error: "Issued at claim (iat) must be an integer") } // MARK: Audience claims func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"), audience:"maxine")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": ["maxine", "katie"]]) } } func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(try decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret"), audience:"kyle")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(try decode(jwt, algorithm: .HS256("secret"), audience:"maxine")) + assertFailure(try decode(jwt, algorithm: .hs256("secret"), audience:"maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .HS256("secret"), audience:"kyle")) + assertFailure(try decode(jwt, algorithm: .hs256("secret"), audience:"kyle")) } // MARK: Signature verification func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(try decode(jwt, algorithm:.None)) { payload in + assertSuccess(try decode(jwt, algorithm:.none)) { payload in XCTAssertEqual(payload as NSDictionary, ["test": "ing"]) } } func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertFailure(try decode(jwt, algorithm: .HS256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret"))) } func testMatchesAnyAlgorithm() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." - assertFailure(try decode(jwt, algorithms: [.HS256("anothersecret"), .HS256("secret")])) + assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret"), .hs256("secret")])) } func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" - assertSuccess(try decode(jwt, algorithm: .HS384("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs384("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" - assertSuccess(try decode(jwt, algorithm: .HS512("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs512("secret"))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } @@ -257,7 +257,7 @@ class JWTDecodeTests : XCTestCase { // MARK: Helpers -func assertSuccess(@autoclosure decoder:() throws -> Payload, closure:(Payload -> ())? = nil) { +func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure:((Payload) -> ())? = nil) { do { let payload = try decoder() closure?(payload) @@ -266,7 +266,7 @@ func assertSuccess(@autoclosure decoder:() throws -> Payload, closure:(Payload - } } -func assertFailure(@autoclosure decoder:() throws -> Payload, closure:(InvalidToken -> ())? = nil) { +func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure:((InvalidToken) -> ())? = nil) { do { _ = try decoder() XCTFail("Decoding succeeded, expected a failure.") @@ -277,10 +277,10 @@ func assertFailure(@autoclosure decoder:() throws -> Payload, closure:(InvalidTo } } -func assertDecodeError(@autoclosure decoder:() throws -> Payload, error:String) { +func assertDecodeError(_ decoder:@autoclosure () throws -> Payload, error:String) { assertFailure(try decoder()) { failure in switch failure { - case .DecodeError(let decodeError): + case .decodeError(let decodeError): if decodeError != error { XCTFail("Incorrect decode error \(decodeError) != \(error)") } diff --git a/README.md b/README.md index 61e156e..b4ecb4a 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ JWT.encode(["my": "payload"], algorithm: .HS256("secret")) #### Building a JWT with the builder pattern ```swift -JWT.encode(.HS256("secret")) { builder in +JWT.encode(.hs256("secret")) { builder in builder.issuer = "fuller.li" - builder.issuedAt = NSDate() + builder.issuedAt = Date() builder["custom"] = "Hi" } ``` @@ -40,7 +40,7 @@ When decoding a JWT, you must supply one or more algorithms and keys. ```swift do { - let payload = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .HS256("secret")) + let payload = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret")) print(payload) } catch { print("Failed to decode JWT: \(error)") @@ -50,7 +50,7 @@ do { When the JWT may be signed with one out of many algorithms or keys: ```swift -try JWT.decode("eyJh...5w", algorithms: [.HS256("secret"), .HS256("secret2"), .HS512("secure")]) +try JWT.decode("eyJh...5w", algorithms: [.hs256("secret"), .hs256("secret2"), .hs512("secure")]) ``` #### Supported claims @@ -67,10 +67,10 @@ The library supports validating the following claims: This library supports the following algorithms: -- None - Unsecured JWTs -- HS256 - HMAC using SHA-256 hash algorithm (default) -- HS384 - HMAC using SHA-384 hash algorithm -- HS512 - HMAC using SHA-512 hash algorithm +- `none` - Unsecured JWTs +- `hs256` - HMAC using SHA-256 hash algorithm (default) +- `hs384` - HMAC using SHA-384 hash algorithm +- `hs512` - HMAC using SHA-512 hash algorithm ## License diff --git a/Sources/Base64.swift b/Sources/Base64.swift index b88162f..32b18cf 100644 --- a/Sources/Base64.swift +++ b/Sources/Base64.swift @@ -2,27 +2,27 @@ import Foundation /// URI Safe base64 encode -func base64encode(input:NSData) -> String { - let data = input.base64EncodedDataWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) - let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String +func base64encode(_ input:Data) -> String { + let data = input.base64EncodedData(options: NSData.Base64EncodingOptions(rawValue: 0)) + let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String return string - .stringByReplacingOccurrencesOfString("+", withString: "-", options: NSStringCompareOptions(rawValue: 0), range: nil) - .stringByReplacingOccurrencesOfString("/", withString: "_", options: NSStringCompareOptions(rawValue: 0), range: nil) - .stringByReplacingOccurrencesOfString("=", withString: "", options: NSStringCompareOptions(rawValue: 0), range: nil) + .replacingOccurrences(of: "+", with: "-", options: NSString.CompareOptions(rawValue: 0), range: nil) + .replacingOccurrences(of: "/", with: "_", options: NSString.CompareOptions(rawValue: 0), range: nil) + .replacingOccurrences(of: "=", with: "", options: NSString.CompareOptions(rawValue: 0), range: nil) } /// URI Safe base64 decode -func base64decode(input:String) -> NSData? { +func base64decode(_ input:String) -> Data? { let rem = input.characters.count % 4 var ending = "" if rem > 0 { let amount = 4 - rem - ending = String(count: amount, repeatedValue: Character("=")) + ending = String(repeating: "=", count: amount) } - let base64 = input.stringByReplacingOccurrencesOfString("-", withString: "+", options: NSStringCompareOptions(rawValue: 0), range: nil) - .stringByReplacingOccurrencesOfString("_", withString: "/", options: NSStringCompareOptions(rawValue: 0), range: nil) + ending + let base64 = input.replacingOccurrences(of: "-", with: "+", options: NSString.CompareOptions(rawValue: 0), range: nil) + .replacingOccurrences(of: "_", with: "/", options: NSString.CompareOptions(rawValue: 0), range: nil) + ending - return NSData(base64EncodedString: base64, options: NSDataBase64DecodingOptions(rawValue: 0)) + return Data(base64Encoded: base64, options: NSData.Base64DecodingOptions(rawValue: 0)) } diff --git a/Sources/Claims.swift b/Sources/Claims.swift index fe7141b..2b3f33d 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,52 +1,52 @@ import Foundation -func validateClaims(payload:Payload, audience:String?, issuer:String?) -> InvalidToken? { +func validateClaims(_ payload:Payload, audience:String?, issuer:String?) -> InvalidToken? { return validateIssuer(payload, issuer: issuer) ?? validateAudience(payload, audience: audience) ?? - validateDate(payload, key: "exp", comparison: .OrderedAscending, failure: .ExpiredSignature, decodeError: "Expiration time claim (exp) must be an integer") ?? - validateDate(payload, key: "nbf", comparison: .OrderedDescending, failure: .ImmatureSignature, decodeError: "Not before claim (nbf) must be an integer") ?? - validateDate(payload, key: "iat", comparison: .OrderedDescending, failure: .InvalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") + validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") ?? + validateDate(payload, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") ?? + validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") } -func validateAudience(payload:Payload, audience:String?) -> InvalidToken? { +func validateAudience(_ payload:Payload, audience:String?) -> InvalidToken? { if let audience = audience { if let aud = payload["aud"] as? [String] { if !aud.contains(audience) { - return .InvalidAudience + return .invalidAudience } } else if let aud = payload["aud"] as? String { if aud != audience { - return .InvalidAudience + return .invalidAudience } } else { - return .DecodeError("Invalid audience claim, must be a string or an array of strings") + return .decodeError("Invalid audience claim, must be a string or an array of strings") } } return nil } -func validateIssuer(payload:Payload, issuer:String?) -> InvalidToken? { +func validateIssuer(_ payload:Payload, issuer:String?) -> InvalidToken? { if let issuer = issuer { if let iss = payload["iss"] as? String { if iss != issuer { - return .InvalidIssuer + return .invalidIssuer } } else { - return .InvalidIssuer + return .invalidIssuer } } return nil } -func validateDate(payload:Payload, key:String, comparison:NSComparisonResult, failure:InvalidToken, decodeError:String) -> InvalidToken? { - if let timestamp = payload[key] as? NSTimeInterval ?? payload[key]?.doubleValue as NSTimeInterval? { - let date = NSDate(timeIntervalSince1970: timestamp) - if date.compare(NSDate()) == comparison { +func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) -> InvalidToken? { + if let timestamp = payload[key] as? TimeInterval ?? (payload[key] as? NSString)?.doubleValue as TimeInterval? { + let date = Date(timeIntervalSince1970: timestamp) + if date.compare(Date()) == comparison { return failure } } else if payload[key] != nil { - return .DecodeError(decodeError) + return .decodeError(decodeError) } return nil diff --git a/Sources/Decode.swift b/Sources/Decode.swift index c22a710..4ec9642 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -2,44 +2,44 @@ import Foundation /// Failure reasons from decoding a JWT -public enum InvalidToken : CustomStringConvertible, ErrorType { +public enum InvalidToken : CustomStringConvertible, Error { /// Decoding the JWT itself failed - case DecodeError(String) + case decodeError(String) /// The JWT uses an unsupported algorithm - case InvalidAlgorithm + case invalidAlgorithm /// The issued claim has expired - case ExpiredSignature + case expiredSignature /// The issued claim is for the future - case ImmatureSignature + case immatureSignature /// The claim is for the future - case InvalidIssuedAt + case invalidIssuedAt /// The audience of the claim doesn't match - case InvalidAudience + case invalidAudience /// The issuer claim failed to verify - case InvalidIssuer + case invalidIssuer /// Returns a readable description of the error public var description:String { switch self { - case .DecodeError(let error): + case .decodeError(let error): return "Decode Error: \(error)" - case .InvalidIssuer: + case .invalidIssuer: return "Invalid Issuer" - case .ExpiredSignature: + case .expiredSignature: return "Expired Signature" - case .ImmatureSignature: + case .immatureSignature: return "The token is not yet valid (not before claim)" - case .InvalidIssuedAt: + case .invalidIssuedAt: return "Issued at claim (iat) is in the future" - case InvalidAudience: + case .invalidAudience: return "Invalid Audience" - case InvalidAlgorithm: + case .invalidAlgorithm: return "Unsupported algorithm or incorrect key" } } @@ -47,9 +47,9 @@ public enum InvalidToken : CustomStringConvertible, ErrorType { /// Decode a JWT -public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) throws -> Payload { +public func decode(_ jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) throws -> Payload { switch load(jwt) { - case let .Success(header, payload, signature, signatureInput): + case let .success(header, payload, signature, signatureInput): if verify { if let failure = validateClaims(payload, audience: audience, issuer: issuer) ?? verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) { throw failure @@ -57,27 +57,27 @@ public func decode(jwt:String, algorithms:[Algorithm], verify:Bool = true, audie } return payload - case .Failure(let failure): + case .failure(let failure): throw failure } } /// Decode a JWT -public func decode(jwt:String, algorithm:Algorithm, verify:Bool = true, audience:String? = nil, issuer:String? = nil) throws -> Payload { +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) } // MARK: Parsing a JWT enum LoadResult { - case Success(header:Payload, payload:Payload, signature:NSData, signatureInput:String) - case Failure(InvalidToken) + case success(header:Payload, payload:Payload, signature:Data, signatureInput:String) + case failure(InvalidToken) } -func load(jwt:String) -> LoadResult { - let segments = jwt.componentsSeparatedByString(".") +func load(_ jwt:String) -> LoadResult { + let segments = jwt.components(separatedBy: ".") if segments.count != 3 { - return .Failure(.DecodeError("Not enough segments")) + return .failure(.decodeError("Not enough segments")) } let headerSegment = segments[0] @@ -87,35 +87,35 @@ func load(jwt:String) -> LoadResult { let headerData = base64decode(headerSegment) if headerData == nil { - return .Failure(.DecodeError("Header is not correctly encoded as base64")) + return .failure(.decodeError("Header is not correctly encoded as base64")) } - let header = (try? NSJSONSerialization.JSONObjectWithData(headerData!, options: NSJSONReadingOptions(rawValue: 0))) as? Payload + let header = (try? JSONSerialization.jsonObject(with: headerData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload if header == nil { - return .Failure(.DecodeError("Invalid header")) + return .failure(.decodeError("Invalid header")) } let payloadData = base64decode(payloadSegment) if payloadData == nil { - return .Failure(.DecodeError("Payload is not correctly encoded as base64")) + return .failure(.decodeError("Payload is not correctly encoded as base64")) } - let payload = (try? NSJSONSerialization.JSONObjectWithData(payloadData!, options: NSJSONReadingOptions(rawValue: 0))) as? Payload + let payload = (try? JSONSerialization.jsonObject(with: payloadData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload if payload == nil { - return .Failure(.DecodeError("Invalid payload")) + return .failure(.decodeError("Invalid payload")) } let signature = base64decode(signatureSegment) if signature == nil { - return .Failure(.DecodeError("Signature is not correctly encoded as base64")) + return .failure(.decodeError("Signature is not correctly encoded as base64")) } - return .Success(header:header!, payload:payload!, signature:signature!, signatureInput:signatureInput) + return .success(header:header!, payload:payload!, signature:signature!, signatureInput:signatureInput) } // MARK: Signature Verification -func verifySignature(algorithms:[Algorithm], header:Payload, signingInput:String, signature:NSData) -> InvalidToken? { +func verifySignature(_ algorithms:[Algorithm], header:Payload, signingInput:String, signature:Data) -> InvalidToken? { if let alg = header["alg"] as? String { let matchingAlgorithms = algorithms.filter { algorithm in algorithm.description == alg } let results = matchingAlgorithms.map { algorithm in algorithm.verify(signingInput, signature: signature) } @@ -124,8 +124,8 @@ func verifySignature(algorithms:[Algorithm], header:Payload, signingInput:String return nil } - return .InvalidAlgorithm + return .invalidAlgorithm } - return .DecodeError("Missing Algorithm") + return .decodeError("Missing Algorithm") } diff --git a/Sources/JWT.swift b/Sources/JWT.swift index bd6ba27..867a603 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -1,35 +1,35 @@ import Foundation import CryptoSwift -public typealias Payload = [String:AnyObject] +public typealias Payload = [String: Any] /// The supported Algorithms public enum Algorithm : CustomStringConvertible { /// No Algorithm, i-e, insecure - case None + case none /// HMAC using SHA-256 hash algorithm - case HS256(String) + case hs256(String) /// HMAC using SHA-384 hash algorithm - case HS384(String) + case hs384(String) /// HMAC using SHA-512 hash algorithm - case HS512(String) + case hs512(String) - static func algorithm(name:String, key:String?) -> Algorithm? { + static func algorithm(_ name:String, key:String?) -> Algorithm? { if name == "none" { if key != nil { return nil // We don't allow nil when we configured a key } - return Algorithm.None + return Algorithm.none } else if let key = key { if name == "HS256" { - return .HS256(key) + return .hs256(key) } else if name == "HS384" { - return .HS384(key) + return .hs384(key) } else if name == "HS512" { - return .HS512(key) + return .hs512(key) } } @@ -38,49 +38,49 @@ public enum Algorithm : CustomStringConvertible { public var description:String { switch self { - case .None: + case .none: return "none" - case .HS256: + case .hs256: return "HS256" - case .HS384: + case .hs384: return "HS384" - case .HS512: + case .hs512: return "HS512" } } /// Sign a message using the algorithm - func sign(message:String) -> String { - func signHS(key:String, variant:CryptoSwift.HMAC.Variant) -> String { - let keyData = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! - let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! - let mac = Authenticator.HMAC(key: keyData.arrayOfBytes(), variant:variant) + func sign(_ message:String) -> String { + func signHS(_ key:String, variant:CryptoSwift.HMAC.Variant) -> String { + let keyData = key.data(using: String.Encoding.utf8, allowLossyConversion: false)! + let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! + let mac = HMAC(key: keyData.bytes, variant:variant) let result: [UInt8] do { - result = try mac.authenticate(messageData.arrayOfBytes()) + result = try mac.authenticate(messageData.bytes) } catch { result = [] } - return base64encode(NSData.withBytes(result)) + return base64encode(Data(bytes: result)) } switch self { - case .None: + case .none: return "" - case .HS256(let key): + case .hs256(let key): return signHS(key, variant: .sha256) - case .HS384(let key): + case .hs384(let key): return signHS(key, variant: .sha384) - case .HS512(let key): + case .hs512(let key): return signHS(key, variant: .sha512) } } /// Verify a signature for a message using the algorithm - func verify(message:String, signature:NSData) -> Bool { + func verify(_ message:String, signature:Data) -> Bool { return sign(message) == base64encode(signature) } } @@ -92,83 +92,83 @@ public enum Algorithm : CustomStringConvertible { - parameter algorithm: The algorithm to sign the payload with - returns: The JSON web token as a String */ -public func encode(payload:Payload, algorithm:Algorithm) -> String { - func encodeJSON(payload:Payload) -> String? { - if let data = try? NSJSONSerialization.dataWithJSONObject(payload, options: NSJSONWritingOptions(rawValue: 0)) { +public func encode(_ payload:Payload, algorithm:Algorithm) -> String { + func encodeJSON(_ payload:Payload) -> String? { + if let data = try? JSONSerialization.data(withJSONObject: payload, options: JSONSerialization.WritingOptions(rawValue: 0)) { return base64encode(data) } return nil } - let header = encodeJSON(["typ": "JWT", "alg": algorithm.description])! + let header = encodeJSON(["typ": "JWT" as AnyObject, "alg": algorithm.description as AnyObject])! let payload = encodeJSON(payload)! let signingInput = "\(header).\(payload)" let signature = algorithm.sign(signingInput) return "\(signingInput).\(signature)" } -public class PayloadBuilder { +open class PayloadBuilder { var payload = Payload() - public var issuer:String? { + open var issuer:String? { get { return payload["iss"] as? String } set { - payload["iss"] = newValue + payload["iss"] = newValue as AnyObject? } } - public var audience:String? { + open var audience:String? { get { return payload["aud"] as? String } set { - payload["aud"] = newValue + payload["aud"] = newValue as AnyObject? } } - public var expiration:NSDate? { + open var expiration:Date? { get { - if let expiration = payload["exp"] as? NSTimeInterval { - return NSDate(timeIntervalSince1970: expiration) + if let expiration = payload["exp"] as? TimeInterval { + return Date(timeIntervalSince1970: expiration) } return nil } set { - payload["exp"] = newValue?.timeIntervalSince1970 + payload["exp"] = newValue?.timeIntervalSince1970 as AnyObject? } } - public var notBefore:NSDate? { + open var notBefore:Date? { get { - if let notBefore = payload["nbf"] as? NSTimeInterval { - return NSDate(timeIntervalSince1970: notBefore) + if let notBefore = payload["nbf"] as? TimeInterval { + return Date(timeIntervalSince1970: notBefore) } return nil } set { - payload["nbf"] = newValue?.timeIntervalSince1970 + payload["nbf"] = newValue?.timeIntervalSince1970 as AnyObject? } } - public var issuedAt:NSDate? { + open var issuedAt:Date? { get { - if let issuedAt = payload["iat"] as? NSTimeInterval { - return NSDate(timeIntervalSince1970: issuedAt) + if let issuedAt = payload["iat"] as? TimeInterval { + return Date(timeIntervalSince1970: issuedAt) } return nil } set { - payload["iat"] = newValue?.timeIntervalSince1970 + payload["iat"] = newValue?.timeIntervalSince1970 as AnyObject? } } - public subscript(key: String) -> AnyObject? { + open subscript(key: String) -> Any { get { return payload[key] } @@ -178,7 +178,7 @@ public class PayloadBuilder { } } -public func encode(algorithm:Algorithm, closure:(PayloadBuilder -> ())) -> String { +public func encode(_ algorithm:Algorithm, closure:((PayloadBuilder) -> ())) -> String { let builder = PayloadBuilder() closure(builder) return encode(builder.payload, algorithm: algorithm) From 3c357d798670d76ad185e906f7ab802397da2519 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 13 Sep 2016 10:49:30 +0100 Subject: [PATCH 035/127] Release 2.0.0 --- CHANGELOG.md | 7 ++++++- JSONWebToken.podspec | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7deb66..8b09cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # JSON Web Token Changelog -## 0.5.0 + +## 2.0.0 + +This release adds support for Swift 3.0. + +## 1.5.0 This release updates the dependency on CryptoSwift to ~> 0.4.0 which adds support for Swift 2.2. diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 244b162..320bc6f 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '1.5.0' + spec.version = '2.0.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } @@ -10,6 +10,7 @@ Pod::Spec.new do |spec| spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.tvos.deployment_target = '9.0' + spec.watchos.deployment_target = '2.0' spec.requires_arc = true spec.dependency 'CryptoSwift', '~> 0.6.0' spec.module_name = 'JWT' From 414f5b758f9fc54a64ba764e3b2cae9eb2e27808 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 13 Sep 2016 11:29:54 +0100 Subject: [PATCH 036/127] Algorithms should take Data not a String Closes #37 --- CHANGELOG.md | 13 ++++++++++ JWTTests/JWTTests.swift | 53 +++++++++++++++++++++-------------------- README.md | 12 ++++++---- Sources/JWT.swift | 30 ++++------------------- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b09cf0..fcefca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # JSON Web Token Changelog +## Master + +### Breaking + +- Algorithms now take `Data` instead of a `String`. This improves the API + allowing you to use keys that cannot be serialised as a String. + + You can easily convert a String to Data such as in the following example: + + ```swift + .hs256("secret".data(using: .utf8)!) + ``` + ## 2.0.0 This release adds support for Swift 3.0. diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index 4eacf56..eddc6e5 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -1,16 +1,17 @@ +import Foundation import XCTest import JWT class JWTEncodeTests : XCTestCase { func testEncodingJWT() { let payload = ["name": "Kyle"] as Payload - let jwt = JWT.encode(payload, algorithm: .hs256("secret")) + let jwt = JWT.encode(payload, algorithm: .hs256("secret".data(using: .utf8)!)) let fixture = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" XCTAssertEqual(jwt, fixture) } func testEncodingWithBuilder() { - let algorithm = Algorithm.hs256("secret") + let algorithm = Algorithm.hs256("secret".data(using: .utf8)!) let jwt = JWT.encode(algorithm) { builder in builder.issuer = "fuller.li" } @@ -77,7 +78,7 @@ class JWTDecodeTests : XCTestCase { func testDecodingValidJWT() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - assertSuccess(try JWT.decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["name": "Kyle"]) } } @@ -97,37 +98,37 @@ class JWTDecodeTests : XCTestCase { func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"), issuer:"fuller.li")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"fuller.li")) { payload in XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) } } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(try decode(jwt, algorithm: .hs256("secret"), issuer:"querykit.org")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .hs256("secret"), issuer:"fuller.li")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - assertFailure(try decode(jwt, algorithm: .hs256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - assertFailure(try decode(jwt, algorithm: .hs256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testUnexpiredClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) } } @@ -135,7 +136,7 @@ class JWTDecodeTests : XCTestCase { func testUnexpiredClaimString() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["exp": "1728188491"]) } } @@ -144,41 +145,41 @@ class JWTDecodeTests : XCTestCase { func testNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) } } func testNotBeforeClaimString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["nbf": "1428189720"]) } } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(try decode(jwt, algorithm: .hs256("secret")), error: "Not before claim (nbf) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)), error: "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - assertFailure(try decode(jwt, algorithm: .hs256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } // MARK: Issued at claim func testIssuedAtClaimInThePast() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) } } func testIssuedAtClaimInThePastString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["iat": "1428189720"]) } } @@ -186,39 +187,39 @@ class JWTDecodeTests : XCTestCase { func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - assertFailure(try decode(jwt, algorithm: .hs256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testInvalidIssuedAtClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOlsxNzI4MTg4NDkxXX0.ND7QMWtLkXDXH38OaXM3SQgLo3Z5TNgF_pcfWHV_alQ" - assertDecodeError(try decode(jwt, algorithm: .hs256("secret")), error: "Issued at claim (iat) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)), error: "Issued at claim (iat) must be an integer") } // MARK: Audience claims func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"), audience:"maxine")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"maxine")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": ["maxine", "katie"]]) } } func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(try decode(jwt, algorithm: .hs256("secret"), audience:"kyle")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"kyle")) { payload in XCTAssertEqual(payload as NSDictionary, ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(try decode(jwt, algorithm: .hs256("secret"), audience:"maxine")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .hs256("secret"), audience:"kyle")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"kyle")) } // MARK: Signature verification @@ -232,24 +233,24 @@ class JWTDecodeTests : XCTestCase { func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertFailure(try decode(jwt, algorithm: .hs256("secret"))) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testMatchesAnyAlgorithm() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." - assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret"), .hs256("secret")])) + assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret".data(using: .utf8)!), .hs256("secret".data(using: .utf8)!)])) } func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" - assertSuccess(try decode(jwt, algorithm: .hs384("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs384("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" - assertSuccess(try decode(jwt, algorithm: .hs512("secret"))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) } } diff --git a/README.md b/README.md index b4ecb4a..85d5f38 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,13 @@ import JWT ### Encoding a claim ```swift -JWT.encode(["my": "payload"], algorithm: .HS256("secret")) +JWT.encode(["my": "payload"], algorithm: .hs256("secret".data(using: .utf8)!)) ``` #### Building a JWT with the builder pattern ```swift -JWT.encode(.hs256("secret")) { builder in +JWT.encode(.hs256("secret".data(using: .utf8))) { builder in builder.issuer = "fuller.li" builder.issuedAt = Date() builder["custom"] = "Hi" @@ -40,7 +40,7 @@ When decoding a JWT, you must supply one or more algorithms and keys. ```swift do { - let payload = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret")) + let payload = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret".data(using: .utf8)!)) print(payload) } catch { print("Failed to decode JWT: \(error)") @@ -50,7 +50,11 @@ do { When the JWT may be signed with one out of many algorithms or keys: ```swift -try JWT.decode("eyJh...5w", algorithms: [.hs256("secret"), .hs256("secret2"), .hs512("secure")]) +try JWT.decode("eyJh...5w", algorithms: [ + .hs256("secret".data(using: .utf8)!), + .hs256("secret2".data(using: .utf8)!), + .hs512("secure".data(using: .utf8)!) +]) ``` #### Supported claims diff --git a/Sources/JWT.swift b/Sources/JWT.swift index 867a603..84f4809 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -9,32 +9,13 @@ public enum Algorithm : CustomStringConvertible { case none /// HMAC using SHA-256 hash algorithm - case hs256(String) + case hs256(Data) /// HMAC using SHA-384 hash algorithm - case hs384(String) + case hs384(Data) /// HMAC using SHA-512 hash algorithm - case hs512(String) - - static func algorithm(_ name:String, key:String?) -> Algorithm? { - if name == "none" { - if key != nil { - return nil // We don't allow nil when we configured a key - } - return Algorithm.none - } else if let key = key { - if name == "HS256" { - return .hs256(key) - } else if name == "HS384" { - return .hs384(key) - } else if name == "HS512" { - return .hs512(key) - } - } - - return nil - } + case hs512(Data) public var description:String { switch self { @@ -51,10 +32,9 @@ public enum Algorithm : CustomStringConvertible { /// Sign a message using the algorithm func sign(_ message:String) -> String { - func signHS(_ key:String, variant:CryptoSwift.HMAC.Variant) -> String { - let keyData = key.data(using: String.Encoding.utf8, allowLossyConversion: false)! + func signHS(_ key: Data, variant:CryptoSwift.HMAC.Variant) -> String { let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! - let mac = HMAC(key: keyData.bytes, variant:variant) + let mac = HMAC(key: key.bytes, variant:variant) let result: [UInt8] do { result = try mac.authenticate(messageData.bytes) From cc8193c5d302112fd2556e4074a42b567d9cec02 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 13 Sep 2016 11:30:41 +0100 Subject: [PATCH 037/127] Release 2.0.1 --- CHANGELOG.md | 7 +++---- JSONWebToken.podspec | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcefca5..8d55f61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # JSON Web Token Changelog -## Master +## 2.0.1 + +This release adds support for Swift 3.0. ### Breaking @@ -13,9 +15,6 @@ .hs256("secret".data(using: .utf8)!) ``` -## 2.0.0 - -This release adds support for Swift 3.0. ## 1.5.0 diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 320bc6f..8308799 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '2.0.0' + spec.version = '2.0.1' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 1e3d5918410dd4b63af7f0b970e56a8a5b25729c Mon Sep 17 00:00:00 2001 From: Hamilton Chapman Date: Fri, 21 Oct 2016 15:21:30 +0100 Subject: [PATCH 038/127] Update Cryptoswift dependency to 0.6.1 (#50) --- Cartfile | 2 +- Cartfile.resolved | 2 +- Carthage/Checkouts/CryptoSwift | 2 +- JSONWebToken.podspec | 2 +- Package.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cartfile b/Cartfile index b5f890d..4f0cac5 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" ~> 0.6.0 +github "krzyzanowskim/CryptoSwift" ~> 0.6.1 diff --git a/Cartfile.resolved b/Cartfile.resolved index 5909a7d..5b562e4 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "krzyzanowskim/CryptoSwift" "0.6.0" +github "krzyzanowskim/CryptoSwift" "0.6.1" diff --git a/Carthage/Checkouts/CryptoSwift b/Carthage/Checkouts/CryptoSwift index fd7bd48..5f9bb95 160000 --- a/Carthage/Checkouts/CryptoSwift +++ b/Carthage/Checkouts/CryptoSwift @@ -1 +1 @@ -Subproject commit fd7bd483a67ab19351db38248ff82a26d8df7cbe +Subproject commit 5f9bb95c6f246c7e19bf4346a6ad1a0c406415f0 diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 8308799..4e225fa 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -12,6 +12,6 @@ Pod::Spec.new do |spec| spec.tvos.deployment_target = '9.0' spec.watchos.deployment_target = '2.0' spec.requires_arc = true - spec.dependency 'CryptoSwift', '~> 0.6.0' + spec.dependency 'CryptoSwift', '~> 0.6.1' spec.module_name = 'JWT' end diff --git a/Package.swift b/Package.swift index cd938aa..0a0d191 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,6 @@ import PackageDescription let package = Package( name: "JWT", dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0, 6, 0) ..< Version(0, 7, 0)) + .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0, 6, 1) ..< Version(0, 7, 0)) ] ) From a6574d510bc5c30b698cdc844d932ab211fe29bb Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 02:39:26 +0000 Subject: [PATCH 039/127] refactor: Make internal validators throwing --- Sources/Claims.swift | 37 ++++++++++++++++--------------------- Sources/Decode.swift | 13 ++++++------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/Sources/Claims.swift b/Sources/Claims.swift index 2b3f33d..61c7f65 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,53 +1,48 @@ import Foundation -func validateClaims(_ payload:Payload, audience:String?, issuer:String?) -> InvalidToken? { - return validateIssuer(payload, issuer: issuer) ?? validateAudience(payload, audience: audience) ?? - validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") ?? - validateDate(payload, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") ?? - validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") +func validateClaims(_ payload:Payload, audience:String?, issuer:String?) throws { + try validateIssuer(payload, issuer: issuer) + try validateAudience(payload, audience: audience) + try validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") + try validateDate(payload, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") + try validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") } -func validateAudience(_ payload:Payload, audience:String?) -> InvalidToken? { +func validateAudience(_ payload:Payload, audience:String?) throws { if let audience = audience { if let aud = payload["aud"] as? [String] { if !aud.contains(audience) { - return .invalidAudience + throw InvalidToken.invalidAudience } } else if let aud = payload["aud"] as? String { if aud != audience { - return .invalidAudience + throw InvalidToken.invalidAudience } } else { - return .decodeError("Invalid audience claim, must be a string or an array of strings") + throw InvalidToken.decodeError("Invalid audience claim, must be a string or an array of strings") } } - - return nil } -func validateIssuer(_ payload:Payload, issuer:String?) -> InvalidToken? { +func validateIssuer(_ payload:Payload, issuer:String?) throws { if let issuer = issuer { if let iss = payload["iss"] as? String { if iss != issuer { - return .invalidIssuer + throw InvalidToken.invalidIssuer } } else { - return .invalidIssuer + throw InvalidToken.invalidIssuer } } - - return nil } -func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) -> InvalidToken? { +func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) throws { if let timestamp = payload[key] as? TimeInterval ?? (payload[key] as? NSString)?.doubleValue as TimeInterval? { let date = Date(timeIntervalSince1970: timestamp) if date.compare(Date()) == comparison { - return failure + throw failure } } else if payload[key] != nil { - return .decodeError(decodeError) + throw InvalidToken.decodeError(decodeError) } - - return nil } diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 4ec9642..5533e74 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -51,9 +51,8 @@ public func decode(_ jwt:String, algorithms:[Algorithm], verify:Bool = true, aud switch load(jwt) { case let .success(header, payload, signature, signatureInput): if verify { - if let failure = validateClaims(payload, audience: audience, issuer: issuer) ?? verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) { - throw failure - } + try validateClaims(payload, audience: audience, issuer: issuer) + try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) } return payload @@ -115,17 +114,17 @@ func load(_ jwt:String) -> LoadResult { // MARK: Signature Verification -func verifySignature(_ algorithms:[Algorithm], header:Payload, signingInput:String, signature:Data) -> InvalidToken? { +func verifySignature(_ algorithms:[Algorithm], header:Payload, signingInput:String, signature:Data) throws { if let alg = header["alg"] as? String { let matchingAlgorithms = algorithms.filter { algorithm in algorithm.description == alg } let results = matchingAlgorithms.map { algorithm in algorithm.verify(signingInput, signature: signature) } let successes = results.filter { $0 } if successes.count > 0 { - return nil + return } - return .invalidAlgorithm + throw InvalidToken.invalidAlgorithm } - return .decodeError("Missing Algorithm") + throw InvalidToken.decodeError("Missing Algorithm") } From 2d2a67f811c096d38250dd0438e9de17363a02d3 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 02:43:34 +0000 Subject: [PATCH 040/127] refactor(decode): Use throwing methods instead of result type --- Sources/Decode.swift | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 5533e74..f8272da 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -48,17 +48,13 @@ public enum InvalidToken : CustomStringConvertible, Error { /// Decode a JWT public func decode(_ jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) throws -> Payload { - switch load(jwt) { - case let .success(header, payload, signature, signatureInput): - if verify { - try validateClaims(payload, audience: audience, issuer: issuer) - try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) - } - - return payload - case .failure(let failure): - throw failure + let (header, payload, signature, signatureInput) = try load(jwt) + if verify { + try validateClaims(payload, audience: audience, issuer: issuer) + try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) } + + return payload } /// Decode a JWT @@ -68,15 +64,10 @@ public func decode(_ jwt:String, algorithm:Algorithm, verify:Bool = true, audien // MARK: Parsing a JWT -enum LoadResult { - case success(header:Payload, payload:Payload, signature:Data, signatureInput:String) - case failure(InvalidToken) -} - -func load(_ jwt:String) -> LoadResult { +func load(_ jwt:String) throws -> (header: Payload, payload: Payload, signature: Data, signatureInput: String) { let segments = jwt.components(separatedBy: ".") if segments.count != 3 { - return .failure(.decodeError("Not enough segments")) + throw InvalidToken.decodeError("Not enough segments") } let headerSegment = segments[0] @@ -86,30 +77,30 @@ func load(_ jwt:String) -> LoadResult { let headerData = base64decode(headerSegment) if headerData == nil { - return .failure(.decodeError("Header is not correctly encoded as base64")) + throw InvalidToken.decodeError("Header is not correctly encoded as base64") } let header = (try? JSONSerialization.jsonObject(with: headerData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload if header == nil { - return .failure(.decodeError("Invalid header")) + throw InvalidToken.decodeError("Invalid header") } let payloadData = base64decode(payloadSegment) if payloadData == nil { - return .failure(.decodeError("Payload is not correctly encoded as base64")) + throw InvalidToken.decodeError("Payload is not correctly encoded as base64") } let payload = (try? JSONSerialization.jsonObject(with: payloadData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload if payload == nil { - return .failure(.decodeError("Invalid payload")) + throw InvalidToken.decodeError("Invalid payload") } let signature = base64decode(signatureSegment) if signature == nil { - return .failure(.decodeError("Signature is not correctly encoded as base64")) + throw InvalidToken.decodeError("Signature is not correctly encoded as base64") } - return .success(header:header!, payload:payload!, signature:signature!, signatureInput:signatureInput) + return (header: header!, payload: payload!, signature: signature!, signatureInput: signatureInput) } // MARK: Signature Verification From aabdb2c6a1372d8689c18e8da325b35d11bd2a5d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 02:46:15 +0000 Subject: [PATCH 041/127] refactor(tests): Remove class prefixes --- JWTTests/JWTTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/JWTTests/JWTTests.swift b/JWTTests/JWTTests.swift index eddc6e5..ac6b353 100644 --- a/JWTTests/JWTTests.swift +++ b/JWTTests/JWTTests.swift @@ -2,7 +2,7 @@ import Foundation import XCTest import JWT -class JWTEncodeTests : XCTestCase { +class EncodeTests: XCTestCase { func testEncodingJWT() { let payload = ["name": "Kyle"] as Payload let jwt = JWT.encode(payload, algorithm: .hs256("secret".data(using: .utf8)!)) @@ -22,7 +22,7 @@ class JWTEncodeTests : XCTestCase { } } -class JWTPayloadBuilder : XCTestCase { +class PayloadTests: XCTestCase { func testIssuer() { JWT.encode(.none) { builder in builder.issuer = "fuller.li" @@ -74,7 +74,7 @@ class JWTPayloadBuilder : XCTestCase { } } -class JWTDecodeTests : XCTestCase { +class DecodeTests: XCTestCase { func testDecodingValidJWT() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" From 23e575c1bf487b2b7b2484d518fc4706e2be0d25 Mon Sep 17 00:00:00 2001 From: Siemen Sikkema Date: Wed, 28 Sep 2016 21:54:27 +0200 Subject: [PATCH 042/127] Perform recommended project changes --- JWT.xcodeproj/project.pbxproj | 17 ++++++++++++++--- .../xcshareddata/xcschemes/JWT-OSX.xcscheme | 2 +- .../xcshareddata/xcschemes/JWT-iOS.xcscheme | 2 +- .../xcshareddata/xcschemes/JWT-tvOS.xcscheme | 2 +- .../xcshareddata/xcschemes/JWT-watchOS.xcscheme | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 86147ea..159ef93 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -357,7 +357,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Cocode; TargetAttributes = { 279D639B1AD07FFF0024E2BC = { @@ -532,8 +532,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -542,6 +544,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -579,8 +582,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -589,6 +594,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -599,6 +605,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -676,7 +683,7 @@ CD9B62211C7753D8005D4844 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -695,7 +702,7 @@ CD9B62221C7753D8005D4844 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -715,6 +722,7 @@ CD9B62331C7753EC005D4844 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -733,6 +741,7 @@ CD9B62341C7753EC005D4844 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -752,6 +761,7 @@ CD9B62451C7753FB005D4844 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -770,6 +780,7 @@ CD9B62461C7753FB005D4844 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme index 1d4884e..ff0db9d 100644 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 2 Dec 2016 03:40:35 +0000 Subject: [PATCH 043/127] refactor: Use guard where possible --- Sources/Claims.swift | 30 ++++++++++++++++-------------- Sources/Decode.swift | 10 ++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Sources/Claims.swift b/Sources/Claims.swift index 61c7f65..3d721d4 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,6 +1,6 @@ import Foundation -func validateClaims(_ payload:Payload, audience:String?, issuer:String?) throws { +func validateClaims(_ payload: Payload, audience: String?, issuer: String?) throws { try validateIssuer(payload, issuer: issuer) try validateAudience(payload, audience: audience) try validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") @@ -8,23 +8,25 @@ func validateClaims(_ payload:Payload, audience:String?, issuer:String?) throws try validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") } -func validateAudience(_ payload:Payload, audience:String?) throws { - if let audience = audience { - if let aud = payload["aud"] as? [String] { - if !aud.contains(audience) { - throw InvalidToken.invalidAudience - } - } else if let aud = payload["aud"] as? String { - if aud != audience { - throw InvalidToken.invalidAudience - } - } else { - throw InvalidToken.decodeError("Invalid audience claim, must be a string or an array of strings") +func validateAudience(_ payload: Payload, audience: String?) throws { + guard let audience = audience else { + return + } + + if let aud = payload["aud"] as? [String] { + if !aud.contains(audience) { + throw InvalidToken.invalidAudience + } + } else if let aud = payload["aud"] as? String { + if aud != audience { + throw InvalidToken.invalidAudience } + } else { + throw InvalidToken.decodeError("Invalid audience claim, must be a string or an array of strings") } } -func validateIssuer(_ payload:Payload, issuer:String?) throws { +func validateIssuer(_ payload: Payload, issuer: String?) throws { if let issuer = issuer { if let iss = payload["iss"] as? String { if iss != issuer { diff --git a/Sources/Decode.swift b/Sources/Decode.swift index f8272da..8d8b6c1 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -75,12 +75,11 @@ func load(_ jwt:String) throws -> (header: Payload, payload: Payload, signature: let signatureSegment = segments[2] let signatureInput = "\(headerSegment).\(payloadSegment)" - let headerData = base64decode(headerSegment) - if headerData == nil { + guard let headerData = base64decode(headerSegment) else { throw InvalidToken.decodeError("Header is not correctly encoded as base64") } - let header = (try? JSONSerialization.jsonObject(with: headerData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload + let header = (try? JSONSerialization.jsonObject(with: headerData, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload if header == nil { throw InvalidToken.decodeError("Invalid header") } @@ -95,12 +94,11 @@ func load(_ jwt:String) throws -> (header: Payload, payload: Payload, signature: throw InvalidToken.decodeError("Invalid payload") } - let signature = base64decode(signatureSegment) - if signature == nil { + guard let signature = base64decode(signatureSegment) else { throw InvalidToken.decodeError("Signature is not correctly encoded as base64") } - return (header: header!, payload: payload!, signature: signature!, signatureInput: signatureInput) + return (header: header!, payload: payload!, signature: signature, signatureInput: signatureInput) } // MARK: Signature Verification From 50d82362ce1b1817cec86f3136cbce0928df7183 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 04:05:32 +0000 Subject: [PATCH 044/127] refactor: Simplify signature verification --- Sources/Decode.swift | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 8d8b6c1..12fc8f9 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -103,17 +103,16 @@ func load(_ jwt:String) throws -> (header: Payload, payload: Payload, signature: // MARK: Signature Verification -func verifySignature(_ algorithms:[Algorithm], header:Payload, signingInput:String, signature:Data) throws { - if let alg = header["alg"] as? String { - let matchingAlgorithms = algorithms.filter { algorithm in algorithm.description == alg } - let results = matchingAlgorithms.map { algorithm in algorithm.verify(signingInput, signature: signature) } - let successes = results.filter { $0 } - if successes.count > 0 { - return - } +func verifySignature(_ algorithms: [Algorithm], header: Payload, signingInput: String, signature: Data) throws { + guard let alg = header["alg"] as? String else { + throw InvalidToken.decodeError("Missing Algorithm") + } + let verifiedAlgorithms = algorithms + .filter { algorithm in algorithm.description == alg } + .filter { algorithm in algorithm.verify(signingInput, signature: signature) } + + if verifiedAlgorithms.isEmpty { throw InvalidToken.invalidAlgorithm } - - throw InvalidToken.decodeError("Missing Algorithm") } From 6729371f2195bc94c6797bc91fd1e80f4196b3cf Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 04:29:14 +0000 Subject: [PATCH 045/127] feat: Add support for Linux Closes #51 --- Sources/Base64.swift | 2 +- Sources/JWT.swift | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Sources/Base64.swift b/Sources/Base64.swift index 32b18cf..f336ff2 100644 --- a/Sources/Base64.swift +++ b/Sources/Base64.swift @@ -4,7 +4,7 @@ import Foundation /// URI Safe base64 encode func base64encode(_ input:Data) -> String { let data = input.base64EncodedData(options: NSData.Base64EncodingOptions(rawValue: 0)) - let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String + let string = String(data: data, encoding: .utf8)! return string .replacingOccurrences(of: "+", with: "-", options: NSString.CompareOptions(rawValue: 0), range: nil) .replacingOccurrences(of: "/", with: "_", options: NSString.CompareOptions(rawValue: 0), range: nil) diff --git a/Sources/JWT.swift b/Sources/JWT.swift index 84f4809..118a904 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -81,7 +81,7 @@ public func encode(_ payload:Payload, algorithm:Algorithm) -> String { return nil } - let header = encodeJSON(["typ": "JWT" as AnyObject, "alg": algorithm.description as AnyObject])! + let header = encodeJSON(["typ": "JWT", "alg": algorithm.description])! let payload = encodeJSON(payload)! let signingInput = "\(header).\(payload)" let signature = algorithm.sign(signingInput) @@ -91,25 +91,25 @@ public func encode(_ payload:Payload, algorithm:Algorithm) -> String { open class PayloadBuilder { var payload = Payload() - open var issuer:String? { + open var issuer: String? { get { return payload["iss"] as? String } set { - payload["iss"] = newValue as AnyObject? + payload["iss"] = newValue } } - open var audience:String? { + open var audience: String? { get { return payload["aud"] as? String } set { - payload["aud"] = newValue as AnyObject? + payload["aud"] = newValue } } - open var expiration:Date? { + open var expiration: Date? { get { if let expiration = payload["exp"] as? TimeInterval { return Date(timeIntervalSince1970: expiration) @@ -118,11 +118,11 @@ open class PayloadBuilder { return nil } set { - payload["exp"] = newValue?.timeIntervalSince1970 as AnyObject? + payload["exp"] = newValue?.timeIntervalSince1970 } } - open var notBefore:Date? { + open var notBefore: Date? { get { if let notBefore = payload["nbf"] as? TimeInterval { return Date(timeIntervalSince1970: notBefore) @@ -131,11 +131,11 @@ open class PayloadBuilder { return nil } set { - payload["nbf"] = newValue?.timeIntervalSince1970 as AnyObject? + payload["nbf"] = newValue?.timeIntervalSince1970 } } - open var issuedAt:Date? { + open var issuedAt: Date? { get { if let issuedAt = payload["iat"] as? TimeInterval { return Date(timeIntervalSince1970: issuedAt) @@ -144,11 +144,11 @@ open class PayloadBuilder { return nil } set { - payload["iat"] = newValue?.timeIntervalSince1970 as AnyObject? + payload["iat"] = newValue?.timeIntervalSince1970 } } - open subscript(key: String) -> Any { + open subscript(key: String) -> Any? { get { return payload[key] } From 654bc93f6a2df3aa985ffe397f6ae26ee40eea94 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 04:34:04 +0000 Subject: [PATCH 046/127] chore: Allow testing with `swift test` --- .gitignore | 2 ++ JWT.xcodeproj/project.pbxproj | 16 +++++++++------- {JWTTests => Tests/JWTTests}/Info.plist | 0 {JWTTests => Tests/JWTTests}/JWTTests.swift | 0 4 files changed, 11 insertions(+), 7 deletions(-) rename {JWTTests => Tests/JWTTests}/Info.plist (100%) rename {JWTTests => Tests/JWTTests}/JWTTests.swift (100%) diff --git a/.gitignore b/.gitignore index 2295c9c..345bfdb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ xcuserdata/ *.xccheckout +.build/ +Packages/ diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 159ef93..195a96f 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -136,8 +136,8 @@ 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */, 520A711B1C469F440005C709 /* Package.swift */, 520A71121C469F010005C709 /* Sources */, - 279D639E1AD07FFF0024E2BC /* JWT */, - 279D63AB1AD07FFF0024E2BC /* JWTTests */, + 279D639E1AD07FFF0024E2BC /* Sources */, + 279D63AB1AD07FFF0024E2BC /* Tests */, 279D639D1AD07FFF0024E2BC /* Products */, AC8AE547FDAF3DD80EB4DB2F /* Frameworks */, ); @@ -157,12 +157,13 @@ name = Products; sourceTree = ""; }; - 279D639E1AD07FFF0024E2BC /* JWT */ = { + 279D639E1AD07FFF0024E2BC /* Sources */ = { isa = PBXGroup; children = ( 279D63A11AD07FFF0024E2BC /* JWT.h */, 279D639F1AD07FFF0024E2BC /* Supporting Files */, ); + name = Sources; path = JWT; sourceTree = ""; }; @@ -174,13 +175,14 @@ name = "Supporting Files"; sourceTree = ""; }; - 279D63AB1AD07FFF0024E2BC /* JWTTests */ = { + 279D63AB1AD07FFF0024E2BC /* Tests */ = { isa = PBXGroup; children = ( 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */, 279D63AC1AD07FFF0024E2BC /* Supporting Files */, ); - path = JWTTests; + name = Tests; + path = Tests/JWTTests; sourceTree = ""; }; 279D63AC1AD07FFF0024E2BC /* Supporting Files */ = { @@ -658,7 +660,7 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = JWTTests/Info.plist; + INFOPLIST_FILE = Tests/JWTTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -673,7 +675,7 @@ "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); - INFOPLIST_FILE = JWTTests/Info.plist; + INFOPLIST_FILE = Tests/JWTTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/JWTTests/Info.plist b/Tests/JWTTests/Info.plist similarity index 100% rename from JWTTests/Info.plist rename to Tests/JWTTests/Info.plist diff --git a/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift similarity index 100% rename from JWTTests/JWTTests.swift rename to Tests/JWTTests/JWTTests.swift From 8cd089bf0aa5706c283de708f98d5931d33141b1 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 04:49:34 +0000 Subject: [PATCH 047/127] chore: Add support for testing on Linux --- Tests/JWTTests/JWTTests.swift | 41 ++++++++++----------- Tests/LinuxMain.swift | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 Tests/LinuxMain.swift diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index ac6b353..717546e 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -17,14 +17,14 @@ class EncodeTests: XCTestCase { } assertSuccess(try JWT.decode(jwt, algorithm: algorithm)) { payload in - XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) + XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"]) } } } class PayloadTests: XCTestCase { func testIssuer() { - JWT.encode(.none) { builder in + _ = JWT.encode(.none) { builder in builder.issuer = "fuller.li" XCTAssertEqual(builder.issuer, "fuller.li") XCTAssertEqual(builder["iss"] as? String, "fuller.li") @@ -32,7 +32,7 @@ class PayloadTests: XCTestCase { } func testAudience() { - JWT.encode(.none) { builder in + _ = JWT.encode(.none) { builder in builder.audience = "cocoapods" XCTAssertEqual(builder.audience, "cocoapods") XCTAssertEqual(builder["aud"] as? String, "cocoapods") @@ -40,7 +40,7 @@ class PayloadTests: XCTestCase { } func testExpiration() { - JWT.encode(.none) { builder in + _ = JWT.encode(.none) { builder in let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) builder.expiration = date XCTAssertEqual(builder.expiration, date) @@ -49,7 +49,7 @@ class PayloadTests: XCTestCase { } func testNotBefore() { - JWT.encode(.none) { builder in + _ = JWT.encode(.none) { builder in let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) builder.notBefore = date XCTAssertEqual(builder.notBefore, date) @@ -58,7 +58,7 @@ class PayloadTests: XCTestCase { } func testIssuedAt() { - JWT.encode(.none) { builder in + _ = JWT.encode(.none) { builder in let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) builder.issuedAt = date XCTAssertEqual(builder.issuedAt, date) @@ -67,7 +67,7 @@ class PayloadTests: XCTestCase { } func testCustomAttributes() { - JWT.encode(.none) { builder in + _ = JWT.encode(.none) { builder in builder["user"] = "kyle" XCTAssertEqual(builder["user"] as? String, "kyle") } @@ -79,7 +79,7 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" assertSuccess(try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["name": "Kyle"]) + XCTAssertEqual(payload as! [String: String], ["name": "Kyle"]) } } @@ -99,7 +99,7 @@ class DecodeTests: XCTestCase { func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"fuller.li")) { payload in - XCTAssertEqual(payload as NSDictionary, ["iss": "fuller.li"]) + XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"]) } } @@ -129,7 +129,7 @@ class DecodeTests: XCTestCase { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["exp": 1728188491]) + XCTAssertEqual(payload as! [String: Int], ["exp": 1728188491]) } } @@ -137,7 +137,7 @@ class DecodeTests: XCTestCase { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["exp": "1728188491"]) + XCTAssertEqual(payload as! [String: String], ["exp": "1728188491"]) } } @@ -146,14 +146,14 @@ class DecodeTests: XCTestCase { func testNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["nbf": 1428189720]) + XCTAssertEqual(payload as! [String: Int], ["nbf": 1428189720]) } } func testNotBeforeClaimString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["nbf": "1428189720"]) + XCTAssertEqual(payload as! [String: String], ["nbf": "1428189720"]) } } @@ -173,14 +173,14 @@ class DecodeTests: XCTestCase { func testIssuedAtClaimInThePast() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["iat": 1428189720]) + XCTAssertEqual(payload as! [String: Int], ["iat": 1428189720]) } } func testIssuedAtClaimInThePastString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["iat": "1428189720"]) + XCTAssertEqual(payload as! [String: String], ["iat": "1428189720"]) } } @@ -201,14 +201,15 @@ class DecodeTests: XCTestCase { func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"maxine")) { payload in - XCTAssertEqual(payload as NSDictionary, ["aud": ["maxine", "katie"]]) + XCTAssertEqual(payload.count, 1) + XCTAssertEqual(payload["aud"] as! [String], ["maxine", "katie"]) } } func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"kyle")) { payload in - XCTAssertEqual(payload as NSDictionary, ["aud": "kyle"]) + XCTAssertEqual(payload as! [String: String], ["aud": "kyle"]) } } @@ -227,7 +228,7 @@ class DecodeTests: XCTestCase { func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." assertSuccess(try decode(jwt, algorithm:.none)) { payload in - XCTAssertEqual(payload as NSDictionary, ["test": "ing"]) + XCTAssertEqual(payload as! [String: String], ["test": "ing"]) } } @@ -244,14 +245,14 @@ class DecodeTests: XCTestCase { func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" assertSuccess(try decode(jwt, algorithm: .hs384("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) + XCTAssertEqual(payload as! [String: String], ["some": "payload"]) } } func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as NSDictionary, ["some": "payload"]) + XCTAssertEqual(payload as! [String: String], ["some": "payload"]) } } } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..59687aa --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,67 @@ +import XCTest +@testable import JWTTests + + +extension EncodeTests { + static var allTests : [(String, (EncodeTests) -> () throws -> Void)] { + return [ + ("testEncodingJWT", testEncodingJWT), + ("testEncodingWithBuilder", testEncodingWithBuilder), + ] + } +} + + +extension DecodeTests { + static var allTests : [(String, (DecodeTests) -> () throws -> Void)] { + return [ + ("testDecodingValidJWT", testDecodingValidJWT), + ("testFailsToDecodeInvalidStringWithoutThreeSegments", testFailsToDecodeInvalidStringWithoutThreeSegments), + ("testDisablingVerify", testDisablingVerify), + ("testSuccessfulIssuerValidation", testSuccessfulIssuerValidation), + ("testIncorrectIssuerValidation", testIncorrectIssuerValidation), + ("testMissingIssuerValidation", testMissingIssuerValidation), + ("testExpiredClaim", testExpiredClaim), + ("testInvalidExpiaryClaim", testInvalidExpiaryClaim), + ("testUnexpiredClaim", testUnexpiredClaim), + ("testUnexpiredClaimString", testUnexpiredClaimString), + ("testNotBeforeClaim", testNotBeforeClaim), + ("testNotBeforeClaimString", testNotBeforeClaimString), + ("testInvalidNotBeforeClaim", testInvalidNotBeforeClaim), + ("testUnmetNotBeforeClaim", testUnmetNotBeforeClaim), + ("testIssuedAtClaimInThePast", testIssuedAtClaimInThePast), + ("testIssuedAtClaimInThePastString", testIssuedAtClaimInThePastString), + ("testIssuedAtClaimInTheFuture", testIssuedAtClaimInTheFuture), + ("testInvalidIssuedAtClaim", testInvalidIssuedAtClaim), + ("testAudiencesClaim", testAudiencesClaim), + ("testAudienceClaim", testAudienceClaim), + ("testMismatchAudienceClaim", testMismatchAudienceClaim), + ("testMissingAudienceClaim", testMissingAudienceClaim), + ("testNoneAlgorithm", testNoneAlgorithm), + ("testNoneFailsWithSecretAlgorithm", testNoneFailsWithSecretAlgorithm), + ("testMatchesAnyAlgorithm", testMatchesAnyAlgorithm), + ("testHS384Algorithm", testHS384Algorithm), + ("testHS512Algorithm", testHS512Algorithm), + ] + } +} + + +extension PayloadTests { + static var allTests : [(String, (PayloadTests) -> () throws -> Void)] { + return [ + ("testIssuer", testIssuer), + ("testAudience", testAudience), + ("testExpiration", testExpiration), + ("testNotBefore", testNotBefore), + ("testIssuedAt", testIssuedAt), + ("testCustomAttributes", testCustomAttributes), + ] + } +} + +XCTMain([ + testCase(EncodeTests.allTests), + testCase(DecodeTests.allTests), + testCase(PayloadTests.allTests), +]) From d94589218e7a6d26d1d36498cf8e0c01d1483c2b Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 19:24:19 +0000 Subject: [PATCH 048/127] fix: Support validating dates on linux --- Sources/Claims.swift | 31 +++++++++++++++++++++++++------ Tests/JWTTests/JWTTests.swift | 2 +- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Sources/Claims.swift b/Sources/Claims.swift index 3d721d4..c216249 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -39,12 +39,31 @@ func validateIssuer(_ payload: Payload, issuer: String?) throws { } func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) throws { - if let timestamp = payload[key] as? TimeInterval ?? (payload[key] as? NSString)?.doubleValue as TimeInterval? { - let date = Date(timeIntervalSince1970: timestamp) - if date.compare(Date()) == comparison { - throw failure - } - } else if payload[key] != nil { + if payload[key] == nil { + return + } + + guard let date = extractDate(payload: payload, key: key) else { throw InvalidToken.decodeError(decodeError) } + + if date.compare(Date()) == comparison { + throw failure + } +} + +fileprivate func extractDate(payload: Payload, key: String) -> Date? { + if let timestamp = payload[key] as? TimeInterval { + return Date(timeIntervalSince1970: timestamp) + } + + if let timestamp = payload[key] as? Int { + return Date(timeIntervalSince1970: Double(timestamp)) + } + + if let timestampString = payload[key] as? String, let timestamp = Double(timestampString) { + return Date(timeIntervalSince1970: timestamp) + } + + return nil } diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 717546e..f5dc5ae 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -176,7 +176,7 @@ class DecodeTests: XCTestCase { XCTAssertEqual(payload as! [String: Int], ["iat": 1428189720]) } } - + func testIssuedAtClaimInThePastString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in From 7e0c9a4c433993f6cda5288d205b252e352998bd Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 19:31:57 +0000 Subject: [PATCH 049/127] fix(tests): Account for differences in JSON serialization This fixes testing on iOS 8 and Linux. Closes #22 --- Tests/JWTTests/JWTTests.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index f5dc5ae..51d4c18 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -6,8 +6,16 @@ class EncodeTests: XCTestCase { func testEncodingJWT() { let payload = ["name": "Kyle"] as Payload let jwt = JWT.encode(payload, algorithm: .hs256("secret".data(using: .utf8)!)) - let fixture = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - XCTAssertEqual(jwt, fixture) + + let expected = [ + // { "alg": "HS256", "typ": "JWT" } + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg", + + // { "typ": "JWT", "alg": "HS256" } + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiS3lsZSJ9.4tCpoxfyfjbUyLjm9_zu-r52Vxn6bFq9kp6Rt9xMs4A", + ] + + XCTAssertTrue(expected.contains(jwt)) } func testEncodingWithBuilder() { From 72d693f2818259d1c795dd9ce8aede2cb36dbbc1 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 19:33:18 +0000 Subject: [PATCH 050/127] chore: Release 2.0.2 --- CHANGELOG.md | 7 +++++++ JSONWebToken.podspec | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d55f61..e9f9614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # JSON Web Token Changelog +## 2.0.2 + +### Enhancements + +- Adds support for Linux. + + ## 2.0.1 This release adds support for Swift 3.0. diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 4e225fa..c718cb1 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '2.0.1' + spec.version = '2.0.2' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From feb252ece1e411538556f69a10416555359e73e5 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 22:18:46 +0000 Subject: [PATCH 051/127] feat: Introduce a ClaimSet --- JWT.xcodeproj/project.pbxproj | 10 ++ Sources/ClaimSet.swift | 199 ++++++++++++++++++++++++++++++++++ Sources/Claims.swift | 38 ------- Sources/Decode.swift | 25 +++-- Sources/JWT.swift | 99 ++++------------- 5 files changed, 246 insertions(+), 125 deletions(-) create mode 100644 Sources/ClaimSet.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 195a96f..d5ffa45 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -10,6 +10,10 @@ 2734C6A81D88001F00BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; 2734C6A91D88002900BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; 2734C6AA1D88003000BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; + 277794051DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; + 277794061DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; + 277794071DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; + 277794081DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; }; @@ -67,6 +71,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 277794041DF221F800573F3E /* ClaimSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClaimSet.swift; sourceTree = ""; }; 279D639C1AD07FFF0024E2BC /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 279D63A01AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 279D63A11AD07FFF0024E2BC /* JWT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JWT.h; sourceTree = ""; }; @@ -196,6 +201,7 @@ 520A71121C469F010005C709 /* Sources */ = { isa = PBXGroup; children = ( + 277794041DF221F800573F3E /* ClaimSet.swift */, 520A71131C469F010005C709 /* Base64.swift */, 520A71141C469F010005C709 /* Claims.swift */, 520A71151C469F010005C709 /* Decode.swift */, @@ -460,6 +466,7 @@ 520A71181C469F010005C709 /* Claims.swift in Sources */, 520A711A1C469F010005C709 /* JWT.swift in Sources */, 520A71191C469F010005C709 /* Decode.swift in Sources */, + 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, 520A71171C469F010005C709 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -479,6 +486,7 @@ CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, + 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -490,6 +498,7 @@ CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, + 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -501,6 +510,7 @@ CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, + 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/ClaimSet.swift b/Sources/ClaimSet.swift new file mode 100644 index 0000000..58c61d4 --- /dev/null +++ b/Sources/ClaimSet.swift @@ -0,0 +1,199 @@ +public struct ClaimSet { + var claims: [String: Any] + + public init(claims: [String: Any]? = nil) { + self.claims = claims ?? [:] + } + + public subscript(key: String) -> Any? { + get { + return claims[key] + } + + set { + if let newValue = newValue, let date = newValue as? Date { + claims[key] = date.timeIntervalSince1970 + } else { + claims[key] = newValue + } + } + } +} + + +// MARK: Accessors + +extension ClaimSet { + public var issuer: String? { + get { + return claims["iss"] as? String + } + + set { + claims["iss"] = newValue + } + } + + public var audience: String? { + get { + return claims["aud"] as? String + } + + set { + claims["aud"] = newValue + } + } + + public var expiration: Date? { + get { + if let expiration = claims["exp"] as? TimeInterval { + return Date(timeIntervalSince1970: expiration) + } + + return nil + } + + set { + self["exp"] = newValue + } + } + + public var notBefore: Date? { + get { + if let notBefore = claims["nbf"] as? TimeInterval { + return Date(timeIntervalSince1970: notBefore) + } + + return nil + } + + set { + self["nbf"] = newValue + } + } + + public var issuedAt: Date? { + get { + if let issuedAt = claims["iat"] as? TimeInterval { + return Date(timeIntervalSince1970: issuedAt) + } + + return nil + } + + set { + self["iat"] = newValue + } + } +} + + +// MARK: Validations + +extension ClaimSet { + func validate(audience: String? = nil, issuer: String? = nil) throws { + if let issuer = issuer { + try validateIssuer(issuer) + } + + if let audience = audience { + try validateAudience(audience) + } + + try validateDate(claims, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") + try validateDate(claims, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") + try validateDate(claims, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") + } + + func validateAudience(_ audience: String) throws { + if let aud = self["aud"] as? [String] { + if !aud.contains(audience) { + throw InvalidToken.invalidAudience + } + } else if let aud = self["aud"] as? String { + if aud != audience { + throw InvalidToken.invalidAudience + } + } else { + throw InvalidToken.decodeError("Invalid audience claim, must be a string or an array of strings") + } + } + + func validateIssuer(_ issuer: String) throws { + if let iss = self["iss"] as? String { + if iss != issuer { + throw InvalidToken.invalidIssuer + } + } else { + throw InvalidToken.invalidIssuer + } + } +} + +// MARK: Builder + +public class ClaimSetBuilder { + var claims = ClaimSet() + + public var issuer: String? { + get { + return claims.issuer + } + + set { + claims.issuer = newValue + } + } + + public var audience: String? { + get { + return claims.audience + } + + set { + claims.audience = newValue + } + } + + public var expiration: Date? { + get { + return claims.expiration + } + + set { + claims.expiration = newValue + } + } + + public var notBefore: Date? { + get { + return claims.notBefore + } + + set { + claims.notBefore = newValue + } + } + + public var issuedAt: Date? { + get { + return claims.issuedAt + } + + set { + claims.issuedAt = newValue + } + } + + public subscript(key: String) -> Any? { + get { + return claims[key] + } + + set { + claims[key] = newValue + } + } +} + +typealias PayloadBuilder = ClaimSetBuilder diff --git a/Sources/Claims.swift b/Sources/Claims.swift index c216249..097c645 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,43 +1,5 @@ import Foundation -func validateClaims(_ payload: Payload, audience: String?, issuer: String?) throws { - try validateIssuer(payload, issuer: issuer) - try validateAudience(payload, audience: audience) - try validateDate(payload, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") - try validateDate(payload, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") - try validateDate(payload, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") -} - -func validateAudience(_ payload: Payload, audience: String?) throws { - guard let audience = audience else { - return - } - - if let aud = payload["aud"] as? [String] { - if !aud.contains(audience) { - throw InvalidToken.invalidAudience - } - } else if let aud = payload["aud"] as? String { - if aud != audience { - throw InvalidToken.invalidAudience - } - } else { - throw InvalidToken.decodeError("Invalid audience claim, must be a string or an array of strings") - } -} - -func validateIssuer(_ payload: Payload, issuer: String?) throws { - if let issuer = issuer { - if let iss = payload["iss"] as? String { - if iss != issuer { - throw InvalidToken.invalidIssuer - } - } else { - throw InvalidToken.invalidIssuer - } - } -} - func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) throws { if payload[key] == nil { return diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 12fc8f9..0aec2a5 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -47,24 +47,33 @@ public enum InvalidToken : CustomStringConvertible, Error { /// Decode a JWT -public func decode(_ jwt:String, algorithms:[Algorithm], verify:Bool = true, audience:String? = nil, issuer:String? = nil) throws -> Payload { - let (header, payload, signature, signatureInput) = try load(jwt) +func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { + let (header, claims, signature, signatureInput) = try load(jwt) + if verify { - try validateClaims(payload, audience: audience, issuer: issuer) + try claims.validate(audience: audience, issuer: issuer) try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) } - return payload + return claims } + /// Decode a JWT -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) +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 +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: Payload, payload: Payload, signature: Data, signatureInput: String) { +func load(_ jwt:String) throws -> (header: Payload, payload: ClaimSet, signature: Data, signatureInput: String) { let segments = jwt.components(separatedBy: ".") if segments.count != 3 { throw InvalidToken.decodeError("Not enough segments") @@ -98,7 +107,7 @@ func load(_ jwt:String) throws -> (header: Payload, payload: Payload, signature: throw InvalidToken.decodeError("Signature is not correctly encoded as base64") } - return (header: header!, payload: payload!, signature: signature, signatureInput: signatureInput) + return (header: header!, payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput) } // MARK: Signature Verification diff --git a/Sources/JWT.swift b/Sources/JWT.swift index 118a904..da49e0a 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -67,14 +67,14 @@ public enum Algorithm : CustomStringConvertible { // MARK: Encoding -/*** 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 -*/ -public func encode(_ payload:Payload, algorithm:Algorithm) -> String { - func encodeJSON(_ payload:Payload) -> String? { - if let data = try? JSONSerialization.data(withJSONObject: payload, options: JSONSerialization.WritingOptions(rawValue: 0)) { +/*** Encode a set of claims + - parameter claims: The ClaiMSet to sign + - parameter algorithm: The algorithm to sign the payload with + - returns: The JSON web token as a String + */ +public func encode(claims: ClaimSet, algorithm: Algorithm) -> String { + func encodeJSON(_ payload: [String: Any]) -> String? { + if let data = try? JSONSerialization.data(withJSONObject: payload) { return base64encode(data) } @@ -82,84 +82,25 @@ public func encode(_ payload:Payload, algorithm:Algorithm) -> String { } let header = encodeJSON(["typ": "JWT", "alg": algorithm.description])! - let payload = encodeJSON(payload)! + let payload = encodeJSON(claims.claims)! let signingInput = "\(header).\(payload)" let signature = algorithm.sign(signingInput) return "\(signingInput).\(signature)" } -open class PayloadBuilder { - var payload = Payload() - - open var issuer: String? { - get { - return payload["iss"] as? String - } - set { - payload["iss"] = newValue - } - } - - open var audience: String? { - get { - return payload["aud"] as? String - } - set { - payload["aud"] = newValue - } - } - - open var expiration: Date? { - get { - if let expiration = payload["exp"] as? TimeInterval { - return Date(timeIntervalSince1970: expiration) - } - return nil - } - set { - payload["exp"] = newValue?.timeIntervalSince1970 - } - } - - open var notBefore: Date? { - get { - if let notBefore = payload["nbf"] as? TimeInterval { - return Date(timeIntervalSince1970: notBefore) - } - - return nil - } - set { - payload["nbf"] = newValue?.timeIntervalSince1970 - } - } - - open var issuedAt: Date? { - get { - if let issuedAt = payload["iat"] as? TimeInterval { - return Date(timeIntervalSince1970: issuedAt) - } - - return nil - } - set { - payload["iat"] = newValue?.timeIntervalSince1970 - } - } - - open subscript(key: String) -> Any? { - get { - return payload[key] - } - set { - payload[key] = newValue - } - } +/*** 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 +*/ +public func encode(_ payload: Payload, algorithm: Algorithm) -> String { + return encode(claims: ClaimSet(claims: payload), algorithm: algorithm) } -public func encode(_ algorithm:Algorithm, closure:((PayloadBuilder) -> ())) -> String { - let builder = PayloadBuilder() +/// Encode a set of claims using the builder pattern +public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> ())) -> String { + let builder = ClaimSetBuilder() closure(builder) - return encode(builder.payload, algorithm: algorithm) + return encode(claims: builder.claims, algorithm: algorithm) } From f5c79ff6008845a6eda9b07f9b2857b9dc4d394e Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 22:27:55 +0000 Subject: [PATCH 052/127] refactor: Introduce a structure for JOSE headers --- JWT.xcodeproj/project.pbxproj | 10 ++++++++++ Sources/Decode.swift | 8 ++++---- Sources/JOSEHeader.swift | 28 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 Sources/JOSEHeader.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index d5ffa45..e6bd378 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -14,6 +14,10 @@ 277794061DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; 277794071DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; 277794081DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; + 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; + 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; + 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; + 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; }; @@ -72,6 +76,7 @@ /* Begin PBXFileReference section */ 277794041DF221F800573F3E /* ClaimSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClaimSet.swift; sourceTree = ""; }; + 2777940A1DF22BE400573F3E /* JOSEHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JOSEHeader.swift; sourceTree = ""; }; 279D639C1AD07FFF0024E2BC /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 279D63A01AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 279D63A11AD07FFF0024E2BC /* JWT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JWT.h; sourceTree = ""; }; @@ -202,6 +207,7 @@ isa = PBXGroup; children = ( 277794041DF221F800573F3E /* ClaimSet.swift */, + 2777940A1DF22BE400573F3E /* JOSEHeader.swift */, 520A71131C469F010005C709 /* Base64.swift */, 520A71141C469F010005C709 /* Claims.swift */, 520A71151C469F010005C709 /* Decode.swift */, @@ -466,6 +472,7 @@ 520A71181C469F010005C709 /* Claims.swift in Sources */, 520A711A1C469F010005C709 /* JWT.swift in Sources */, 520A71191C469F010005C709 /* Decode.swift in Sources */, + 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, 520A71171C469F010005C709 /* Base64.swift in Sources */, ); @@ -486,6 +493,7 @@ CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, + 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, ); @@ -498,6 +506,7 @@ CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, + 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, ); @@ -510,6 +519,7 @@ CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, + 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, ); diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 0aec2a5..dfc79b5 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -73,7 +73,7 @@ public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, aud // MARK: Parsing a JWT -func load(_ jwt:String) throws -> (header: Payload, payload: ClaimSet, signature: Data, signatureInput: String) { +func load(_ jwt:String) throws -> (header: JOSEHeader, payload: ClaimSet, signature: Data, signatureInput: String) { let segments = jwt.components(separatedBy: ".") if segments.count != 3 { throw InvalidToken.decodeError("Not enough segments") @@ -107,13 +107,13 @@ func load(_ jwt:String) throws -> (header: Payload, payload: ClaimSet, signature throw InvalidToken.decodeError("Signature is not correctly encoded as base64") } - return (header: header!, payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput) + return (header: JOSEHeader(parameters: header!), payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput) } // MARK: Signature Verification -func verifySignature(_ algorithms: [Algorithm], header: Payload, signingInput: String, signature: Data) throws { - guard let alg = header["alg"] as? String else { +func verifySignature(_ algorithms: [Algorithm], header: JOSEHeader, signingInput: String, signature: Data) throws { + guard let alg = header.algorithm else { throw InvalidToken.decodeError("Missing Algorithm") } diff --git a/Sources/JOSEHeader.swift b/Sources/JOSEHeader.swift new file mode 100644 index 0000000..e19453c --- /dev/null +++ b/Sources/JOSEHeader.swift @@ -0,0 +1,28 @@ +// +// JOSEHeader.swift +// JWT +// +// Created by Kyle Fuller on 02/12/2016. +// Copyright © 2016 Cocode. All rights reserved. +// + +import Foundation + + +struct JOSEHeader { + var parameters: [String: Any] + + init(parameters: [String: Any]) { + self.parameters = parameters + } + + var algorithm: String? { + get { + return parameters["alg"] as? String + } + + set { + parameters["alg"] = newValue + } + } +} From 48cd4d6e9f8145213fb1898d67ccd0a48aaced77 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 22:32:30 +0000 Subject: [PATCH 053/127] refactor: Deprecate encode without `claims:` label --- JWT.xcodeproj/project.pbxproj | 10 ++++++++ Sources/Encode.swift | 48 +++++++++++++++++++++++++++++++++++ Sources/JWT.swift | 40 ----------------------------- 3 files changed, 58 insertions(+), 40 deletions(-) create mode 100644 Sources/Encode.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index e6bd378..4158229 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -18,6 +18,10 @@ 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; + 277794101DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; + 277794111DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; + 277794121DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; + 277794131DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; }; @@ -77,6 +81,7 @@ /* Begin PBXFileReference section */ 277794041DF221F800573F3E /* ClaimSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClaimSet.swift; sourceTree = ""; }; 2777940A1DF22BE400573F3E /* JOSEHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JOSEHeader.swift; sourceTree = ""; }; + 2777940F1DF22D0D00573F3E /* Encode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Encode.swift; sourceTree = ""; }; 279D639C1AD07FFF0024E2BC /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 279D63A01AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 279D63A11AD07FFF0024E2BC /* JWT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JWT.h; sourceTree = ""; }; @@ -211,6 +216,7 @@ 520A71131C469F010005C709 /* Base64.swift */, 520A71141C469F010005C709 /* Claims.swift */, 520A71151C469F010005C709 /* Decode.swift */, + 2777940F1DF22D0D00573F3E /* Encode.swift */, 520A71161C469F010005C709 /* JWT.swift */, ); path = Sources; @@ -472,6 +478,7 @@ 520A71181C469F010005C709 /* Claims.swift in Sources */, 520A711A1C469F010005C709 /* JWT.swift in Sources */, 520A71191C469F010005C709 /* Decode.swift in Sources */, + 277794101DF22D0D00573F3E /* Encode.swift in Sources */, 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, 520A71171C469F010005C709 /* Base64.swift in Sources */, @@ -493,6 +500,7 @@ CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, + 277794111DF22D0D00573F3E /* Encode.swift in Sources */, 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, @@ -506,6 +514,7 @@ CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, + 277794121DF22D0D00573F3E /* Encode.swift in Sources */, 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, @@ -519,6 +528,7 @@ CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, + 277794131DF22D0D00573F3E /* Encode.swift in Sources */, 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, diff --git a/Sources/Encode.swift b/Sources/Encode.swift new file mode 100644 index 0000000..7386c1f --- /dev/null +++ b/Sources/Encode.swift @@ -0,0 +1,48 @@ +/*** Encode a set of claims + - parameter claims: The set of claims + - parameter algorithm: The algorithm to sign the payload with + - returns: The JSON web token as a String + */ +public func encode(claims: ClaimSet, algorithm: Algorithm) -> String { + func encodeJSON(_ payload: [String: Any]) -> String? { + if let data = try? JSONSerialization.data(withJSONObject: payload) { + return base64encode(data) + } + + return nil + } + + let header = encodeJSON(["typ": "JWT", "alg": algorithm.description])! + let payload = encodeJSON(claims.claims)! + let signingInput = "\(header).\(payload)" + let signature = algorithm.sign(signingInput) + return "\(signingInput).\(signature)" +} + +/*** Encode a dictionary of claims + - parameter claims: The dictionary of claims + - parameter algorithm: The algorithm to sign the payload with + - returns: The JSON web token as a String + */ +public func encode(claims: [String: Any], algorithm: Algorithm) -> String { + return encode(claims: ClaimSet(claims: claims), algorithm: algorithm) +} + + +/// Encode a set of claims using the builder pattern +public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> ())) -> String { + let builder = ClaimSetBuilder() + 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/Sources/JWT.swift b/Sources/JWT.swift index da49e0a..adb4835 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -64,43 +64,3 @@ public enum Algorithm : CustomStringConvertible { return sign(message) == base64encode(signature) } } - -// MARK: Encoding - -/*** Encode a set of claims - - parameter claims: The ClaiMSet to sign - - parameter algorithm: The algorithm to sign the payload with - - returns: The JSON web token as a String - */ -public func encode(claims: ClaimSet, algorithm: Algorithm) -> String { - func encodeJSON(_ payload: [String: Any]) -> String? { - if let data = try? JSONSerialization.data(withJSONObject: payload) { - return base64encode(data) - } - - return nil - } - - let header = encodeJSON(["typ": "JWT", "alg": algorithm.description])! - let payload = encodeJSON(claims.claims)! - let signingInput = "\(header).\(payload)" - let signature = algorithm.sign(signingInput) - return "\(signingInput).\(signature)" -} - - -/*** 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 -*/ -public func encode(_ payload: Payload, algorithm: Algorithm) -> String { - return encode(claims: ClaimSet(claims: payload), algorithm: algorithm) -} - -/// Encode a set of claims using the builder pattern -public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> ())) -> String { - let builder = ClaimSetBuilder() - closure(builder) - return encode(claims: builder.claims, algorithm: algorithm) -} From 30cb9ea0ed7ed49053461d362c38ad8aa1e67da1 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 22:36:46 +0000 Subject: [PATCH 054/127] refactor: Deprecate decoding to dictionary --- Sources/Decode.swift | 10 +++++++++- Tests/JWTTests/JWTTests.swift | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Sources/Decode.swift b/Sources/Decode.swift index dfc79b5..f34e3b6 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -47,7 +47,7 @@ public enum InvalidToken : CustomStringConvertible, Error { /// Decode a JWT -func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { +public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { let (header, claims, signature, signatureInput) = try load(jwt) if verify { @@ -60,12 +60,20 @@ func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audienc /// Decode a JWT +public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { + return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer) +} + + +/// 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 } diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 51d4c18..15d68f3 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -83,6 +83,13 @@ class PayloadTests: XCTestCase { } 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() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" From ce7285f72150910440857dde53f29ef09718906d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 22:41:30 +0000 Subject: [PATCH 055/127] feat: Document new ClaimSet Closes #45 --- CHANGELOG.md | 9 +++++++++ README.md | 18 ++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9f9614..2917a2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # JSON Web Token Changelog +## Master + +### Enhancements + +- Introduces a new `ClaimSet` structure. The structure can be returned from + `decode` providing you convenience accessors. `encode` will now accept a + `ClaimSet`. + + ## 2.0.2 ### Enhancements diff --git a/README.md b/README.md index 85d5f38..6cb4f1d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,18 @@ import JWT ### Encoding a claim ```swift -JWT.encode(["my": "payload"], algorithm: .hs256("secret".data(using: .utf8)!)) +JWT.encode(claims: ["my": "payload"], algorithm: .hs256("secret".data(using: .utf8)!)) +``` + +#### Encoding a claim set + +```swift +var claims = ClaimSet() +claims.issuer = "fuller.li" +claims.issuedAt = Date() +claims["custom"] = "Hi" + +JWT.encode(claims: claims, algorithm, algorithm: .hs256("secret".data(using: .utf8))) ``` #### Building a JWT with the builder pattern @@ -40,8 +51,8 @@ When decoding a JWT, you must supply one or more algorithms and keys. ```swift do { - let payload = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret".data(using: .utf8)!)) - print(payload) + let claims = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret".data(using: .utf8)!)) + print(claims) } catch { print("Failed to decode JWT: \(error)") } @@ -79,4 +90,3 @@ This library supports the following algorithms: ## License JSONWebToken is licensed under the BSD license. See [LICENSE](LICENSE) for more info. - From e36d4f010af8abd9ee16cb0522926433abd113fc Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 22:46:19 +0000 Subject: [PATCH 056/127] feat(claims): Expose validation APIs Closes #48 Closes #49 --- CHANGELOG.md | 10 ++++++++++ Sources/ClaimSet.swift | 24 ++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2917a2e..2854647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,16 @@ `decode` providing you convenience accessors. `encode` will now accept a `ClaimSet`. + `ClaimSet` provides methods to manually validate individual claims. + + ```swift + try claims.validateAudience("example.com") + try claims.validateIssuer("fuller.li") + try claims.validateExpiary() + try claims.validateNotBefore() + try claims.validateIssuedAt() + ``` + ## 2.0.2 diff --git a/Sources/ClaimSet.swift b/Sources/ClaimSet.swift index 58c61d4..2be08ca 100644 --- a/Sources/ClaimSet.swift +++ b/Sources/ClaimSet.swift @@ -91,7 +91,7 @@ extension ClaimSet { // MARK: Validations extension ClaimSet { - func validate(audience: String? = nil, issuer: String? = nil) throws { + public func validate(audience: String? = nil, issuer: String? = nil) throws { if let issuer = issuer { try validateIssuer(issuer) } @@ -100,12 +100,12 @@ extension ClaimSet { try validateAudience(audience) } - try validateDate(claims, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") - try validateDate(claims, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") - try validateDate(claims, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") + try validateExpiary() + try validateNotBefore() + try validateIssuedAt() } - func validateAudience(_ audience: String) throws { + public func validateAudience(_ audience: String) throws { if let aud = self["aud"] as? [String] { if !aud.contains(audience) { throw InvalidToken.invalidAudience @@ -119,7 +119,7 @@ extension ClaimSet { } } - func validateIssuer(_ issuer: String) throws { + public func validateIssuer(_ issuer: String) throws { if let iss = self["iss"] as? String { if iss != issuer { throw InvalidToken.invalidIssuer @@ -128,6 +128,18 @@ extension ClaimSet { throw InvalidToken.invalidIssuer } } + + public func validateExpiary() throws { + try validateDate(claims, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") + } + + public func validateNotBefore() throws { + try validateDate(claims, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") + } + + public func validateIssuedAt() throws { + try validateDate(claims, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") + } } // MARK: Builder From 8e72a3330a7021938dfe2f0ed15e20d52a71b6c0 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 2 Dec 2016 23:18:42 +0000 Subject: [PATCH 057/127] chore: Align code style --- Package.swift | 2 +- Sources/Base64.swift | 5 ++--- Sources/Claims.swift | 2 +- Sources/Decode.swift | 10 +++------- Sources/Encode.swift | 2 +- Sources/JWT.swift | 12 ++++++------ Tests/JWTTests/JWTTests.swift | 30 +++++++++++++++--------------- Tests/LinuxMain.swift | 8 +++----- 8 files changed, 32 insertions(+), 39 deletions(-) diff --git a/Package.swift b/Package.swift index 0a0d191..f90189c 100644 --- a/Package.swift +++ b/Package.swift @@ -3,6 +3,6 @@ import PackageDescription let package = Package( name: "JWT", dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0, 6, 1) ..< Version(0, 7, 0)) + .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0, 6, 1) ..< Version(0, 7, 0)), ] ) diff --git a/Sources/Base64.swift b/Sources/Base64.swift index f336ff2..c85719b 100644 --- a/Sources/Base64.swift +++ b/Sources/Base64.swift @@ -1,8 +1,7 @@ import Foundation - /// URI Safe base64 encode -func base64encode(_ input:Data) -> String { +func base64encode(_ input: Data) -> String { let data = input.base64EncodedData(options: NSData.Base64EncodingOptions(rawValue: 0)) let string = String(data: data, encoding: .utf8)! return string @@ -12,7 +11,7 @@ func base64encode(_ input:Data) -> String { } /// URI Safe base64 decode -func base64decode(_ input:String) -> Data? { +func base64decode(_ input: String) -> Data? { let rem = input.characters.count % 4 var ending = "" diff --git a/Sources/Claims.swift b/Sources/Claims.swift index 097c645..ad07027 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,6 +1,6 @@ import Foundation -func validateDate(_ payload:Payload, key:String, comparison:ComparisonResult, failure:InvalidToken, decodeError:String) throws { +func validateDate(_ payload: Payload, key: String, comparison: ComparisonResult, failure: InvalidToken, decodeError: String) throws { if payload[key] == nil { return } diff --git a/Sources/Decode.swift b/Sources/Decode.swift index f34e3b6..ce802d7 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -2,7 +2,7 @@ import Foundation /// Failure reasons from decoding a JWT -public enum InvalidToken : CustomStringConvertible, Error { +public enum InvalidToken: CustomStringConvertible, Error { /// Decoding the JWT itself failed case decodeError(String) @@ -25,7 +25,7 @@ public enum InvalidToken : CustomStringConvertible, Error { case invalidIssuer /// Returns a readable description of the error - public var description:String { + public var description: String { switch self { case .decodeError(let error): return "Decode Error: \(error)" @@ -58,30 +58,26 @@ public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, return claims } - /// Decode a JWT public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer) } - /// 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) { +func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signature: Data, signatureInput: String) { let segments = jwt.components(separatedBy: ".") if segments.count != 3 { throw InvalidToken.decodeError("Not enough segments") diff --git a/Sources/Encode.swift b/Sources/Encode.swift index 7386c1f..04f4109 100644 --- a/Sources/Encode.swift +++ b/Sources/Encode.swift @@ -30,7 +30,7 @@ public func encode(claims: [String: Any], algorithm: Algorithm) -> String { /// Encode a set of claims using the builder pattern -public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> ())) -> String { +public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> Void)) -> String { let builder = ClaimSetBuilder() closure(builder) return encode(claims: builder.claims, algorithm: algorithm) diff --git a/Sources/JWT.swift b/Sources/JWT.swift index adb4835..3b3e4a3 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -4,7 +4,7 @@ import CryptoSwift public typealias Payload = [String: Any] /// The supported Algorithms -public enum Algorithm : CustomStringConvertible { +public enum Algorithm: CustomStringConvertible { /// No Algorithm, i-e, insecure case none @@ -17,7 +17,7 @@ public enum Algorithm : CustomStringConvertible { /// HMAC using SHA-512 hash algorithm case hs512(Data) - public var description:String { + public var description: String { switch self { case .none: return "none" @@ -31,10 +31,10 @@ public enum Algorithm : CustomStringConvertible { } /// Sign a message using the algorithm - func sign(_ message:String) -> String { - func signHS(_ key: Data, variant:CryptoSwift.HMAC.Variant) -> String { + func sign(_ message: String) -> String { + func signHS(_ key: Data, variant: CryptoSwift.HMAC.Variant) -> String { let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! - let mac = HMAC(key: key.bytes, variant:variant) + let mac = HMAC(key: key.bytes, variant: variant) let result: [UInt8] do { result = try mac.authenticate(messageData.bytes) @@ -60,7 +60,7 @@ public enum Algorithm : CustomStringConvertible { } /// Verify a signature for a message using the algorithm - func verify(_ message:String, signature:Data) -> Bool { + func verify(_ message: String, signature: Data) -> Bool { return sign(message) == base64encode(signature) } } diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 15d68f3..fe2a83d 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -33,7 +33,7 @@ class EncodeTests: XCTestCase { class PayloadTests: XCTestCase { func testIssuer() { _ = JWT.encode(.none) { builder in - builder.issuer = "fuller.li" + builder.issuer = "fuller.li" XCTAssertEqual(builder.issuer, "fuller.li") XCTAssertEqual(builder["iss"] as? String, "fuller.li") } @@ -106,26 +106,26 @@ class DecodeTests: XCTestCase { func testDisablingVerify() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertSuccess(try decode(jwt, algorithm: .none, verify:false, issuer:"fuller.li")) + assertSuccess(try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li")) } // MARK: Issuer claim func testSuccessfulIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"fuller.li")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) { payload in XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"]) } } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"querykit.org")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer:"fuller.li")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) } // MARK: Expiration claim @@ -147,7 +147,7 @@ class DecodeTests: XCTestCase { XCTAssertEqual(payload as! [String: Int], ["exp": 1728188491]) } } - + func testUnexpiredClaimString() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" @@ -164,7 +164,7 @@ class DecodeTests: XCTestCase { XCTAssertEqual(payload as! [String: Int], ["nbf": 1428189720]) } } - + func testNotBeforeClaimString() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in @@ -215,7 +215,7 @@ class DecodeTests: XCTestCase { func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"maxine")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) { payload in XCTAssertEqual(payload.count, 1) XCTAssertEqual(payload["aud"] as! [String], ["maxine", "katie"]) } @@ -223,26 +223,26 @@ class DecodeTests: XCTestCase { func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"kyle")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) { payload in XCTAssertEqual(payload as! [String: String], ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"maxine")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience:"kyle")) + assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) } // MARK: Signature verification func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(try decode(jwt, algorithm:.none)) { payload in + assertSuccess(try decode(jwt, algorithm: .none)) { payload in XCTAssertEqual(payload as! [String: String], ["test": "ing"]) } } @@ -274,7 +274,7 @@ class DecodeTests: XCTestCase { // MARK: Helpers -func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure:((Payload) -> ())? = nil) { +func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure: ((Payload) -> Void)? = nil) { do { let payload = try decoder() closure?(payload) @@ -283,7 +283,7 @@ func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure:((Paylo } } -func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure:((InvalidToken) -> ())? = nil) { +func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure: ((InvalidToken) -> Void)? = nil) { do { _ = try decoder() XCTFail("Decoding succeeded, expected a failure.") @@ -294,7 +294,7 @@ func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure:((Inval } } -func assertDecodeError(_ decoder:@autoclosure () throws -> Payload, error:String) { +func assertDecodeError(_ decoder: @autoclosure () throws -> Payload, error: String) { assertFailure(try decoder()) { failure in switch failure { case .decodeError(let decodeError): diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 59687aa..b42db82 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -3,7 +3,7 @@ import XCTest extension EncodeTests { - static var allTests : [(String, (EncodeTests) -> () throws -> Void)] { + static var allTests: [(String, (EncodeTests) -> Void throws -> Void)] { return [ ("testEncodingJWT", testEncodingJWT), ("testEncodingWithBuilder", testEncodingWithBuilder), @@ -11,9 +11,8 @@ extension EncodeTests { } } - extension DecodeTests { - static var allTests : [(String, (DecodeTests) -> () throws -> Void)] { + static var allTests: [(String, (DecodeTests) -> Void throws -> Void)] { return [ ("testDecodingValidJWT", testDecodingValidJWT), ("testFailsToDecodeInvalidStringWithoutThreeSegments", testFailsToDecodeInvalidStringWithoutThreeSegments), @@ -46,9 +45,8 @@ extension DecodeTests { } } - extension PayloadTests { - static var allTests : [(String, (PayloadTests) -> () throws -> Void)] { + static var allTests: [(String, (PayloadTests) -> Void throws -> Void)] { return [ ("testIssuer", testIssuer), ("testAudience", testAudience), From f1176762ca97b5e08aa091dfa67f60767f4b7088 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 18 Jan 2017 15:51:17 +0000 Subject: [PATCH 058/127] chore: Release 2.1.0 --- CHANGELOG.md | 2 +- JSONWebToken.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2854647..57b5e8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # JSON Web Token Changelog -## Master +## 2.1.0 ### Enhancements diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index c718cb1..9dce369 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '2.0.2' + spec.version = '2.1.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From b605fe2d53a239946ffa81ab7de32daa71fd4aa4 Mon Sep 17 00:00:00 2001 From: Alexsander Akers Date: Mon, 6 Feb 2017 17:36:47 +0100 Subject: [PATCH 059/127] Add missing Foundation imports (#60) --- Sources/ClaimSet.swift | 2 ++ Sources/Encode.swift | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Sources/ClaimSet.swift b/Sources/ClaimSet.swift index 2be08ca..7626498 100644 --- a/Sources/ClaimSet.swift +++ b/Sources/ClaimSet.swift @@ -1,3 +1,5 @@ +import Foundation + public struct ClaimSet { var claims: [String: Any] diff --git a/Sources/Encode.swift b/Sources/Encode.swift index 04f4109..a864d4c 100644 --- a/Sources/Encode.swift +++ b/Sources/Encode.swift @@ -1,3 +1,5 @@ +import Foundation + /*** Encode a set of claims - parameter claims: The set of claims - parameter algorithm: The algorithm to sign the payload with From c61cdc92173c2348bdcc78a9d4c55be38ebbe938 Mon Sep 17 00:00:00 2001 From: Shane Vitarana Date: Wed, 5 Apr 2017 10:41:07 -0400 Subject: [PATCH 060/127] Updated README with fixed example (#64) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6cb4f1d..830f70d 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ When decoding a JWT, you must supply one or more algorithms and keys. ```swift do { - let claims = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret".data(using: .utf8)!)) + let claims: ClaimSet = try JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w", algorithm: .hs256("secret".data(using: .utf8)!)) print(claims) } catch { print("Failed to decode JWT: \(error)") From 7cb91b9533c735e9d1325ea66be8795fae6e0a74 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 24 Apr 2017 09:59:03 +0100 Subject: [PATCH 061/127] chore: Release 2.1.1 --- JSONWebToken.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 9dce369..2bf5306 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '2.1.0' + spec.version = '2.1.1' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 71e8a01407a0fe5294209c3c2721c217aeb7ea4d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 18 May 2017 14:37:53 +0100 Subject: [PATCH 062/127] chore: Build and test on all supported platforms --- .travis.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37e3d17..10f4bf6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,19 @@ -language: objective-c -osx_image: xcode8 -script: -- set -o pipefail +os: +- linux +- osx +language: generic +sudo: required +dist: trusty +osx_image: xcode8.3 +env: +- SWIFT_VERSION=3.1.1 +install: +- eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" - git submodule update --init --recursive -- xcodebuild -project JWT.xcodeproj -scheme JWT-OSX test -sdk macosx | xcpretty -c -- pod lib lint --quick +script: +- swift test +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-OSX test -sdk macosx; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-iOS build -sdk iphonesimulator; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-tvOS build -sdk appletvsimulator; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-watchOS build -sdk watchsimulator; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint; fi From bf351cfc1a7611fa1146faec5f1b912f819a3764 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 18 May 2017 14:43:45 +0100 Subject: [PATCH 063/127] fix: Testing on Linux --- Tests/LinuxMain.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index b42db82..8488183 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -3,7 +3,7 @@ import XCTest extension EncodeTests { - static var allTests: [(String, (EncodeTests) -> Void throws -> Void)] { + static var allTests: [(String, (EncodeTests) -> (Void) throws -> Void)] { return [ ("testEncodingJWT", testEncodingJWT), ("testEncodingWithBuilder", testEncodingWithBuilder), @@ -12,7 +12,7 @@ extension EncodeTests { } extension DecodeTests { - static var allTests: [(String, (DecodeTests) -> Void throws -> Void)] { + static var allTests: [(String, (DecodeTests) -> (Void) throws -> Void)] { return [ ("testDecodingValidJWT", testDecodingValidJWT), ("testFailsToDecodeInvalidStringWithoutThreeSegments", testFailsToDecodeInvalidStringWithoutThreeSegments), @@ -46,7 +46,7 @@ extension DecodeTests { } extension PayloadTests { - static var allTests: [(String, (PayloadTests) -> Void throws -> Void)] { + static var allTests: [(String, (PayloadTests) -> (Void) throws -> Void)] { return [ ("testIssuer", testIssuer), ("testAudience", testAudience), From da67dfdf4b723ec761113dde790232b60284284d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 18 May 2017 14:54:24 +0100 Subject: [PATCH 064/127] chore(ci): Don't use swiftenv on macOS --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 10f4bf6..41fcf91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ osx_image: xcode8.3 env: - SWIFT_VERSION=3.1.1 install: -- eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" +- if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"; fi - git submodule update --init --recursive script: - swift test From 747857196c62b3ba38d20373d2be093e90bbf412 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 7 Jun 2017 19:05:15 +0200 Subject: [PATCH 065/127] feat: Allow setting custom headers Closes #74 --- CHANGELOG.md | 7 +++++++ Sources/Encode.swift | 14 ++++++++++---- Tests/JWTTests/JWTTests.swift | 7 +++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57b5e8f..bd856eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # JSON Web Token Changelog +## Master + +### Enhancements + +- Allow passing additional headers when encoding a JWT. + + ## 2.1.0 ### Enhancements diff --git a/Sources/Encode.swift b/Sources/Encode.swift index a864d4c..fa716d1 100644 --- a/Sources/Encode.swift +++ b/Sources/Encode.swift @@ -5,7 +5,7 @@ import Foundation - parameter algorithm: The algorithm to sign the payload with - returns: The JSON web token as a String */ -public func encode(claims: ClaimSet, algorithm: Algorithm) -> String { +public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: String]? = nil) -> String { func encodeJSON(_ payload: [String: Any]) -> String? { if let data = try? JSONSerialization.data(withJSONObject: payload) { return base64encode(data) @@ -14,7 +14,13 @@ public func encode(claims: ClaimSet, algorithm: Algorithm) -> String { return nil } - let header = encodeJSON(["typ": "JWT", "alg": algorithm.description])! + var headers = headers ?? [:] + if !headers.keys.contains("typ") { + headers["typ"] = "JWT" + } + headers["alg"] = algorithm.description + + let header = encodeJSON(headers)! let payload = encodeJSON(claims.claims)! let signingInput = "\(header).\(payload)" let signature = algorithm.sign(signingInput) @@ -26,8 +32,8 @@ public func encode(claims: ClaimSet, algorithm: Algorithm) -> String { - parameter algorithm: The algorithm to sign the payload with - returns: The JSON web token as a String */ -public func encode(claims: [String: Any], algorithm: Algorithm) -> String { - return encode(claims: ClaimSet(claims: claims), algorithm: algorithm) +public func encode(claims: [String: Any], algorithm: Algorithm, headers: [String: String]? = nil) -> String { + return encode(claims: ClaimSet(claims: claims), algorithm: algorithm, headers: headers) } diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index fe2a83d..a0e1b8f 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -28,6 +28,13 @@ class EncodeTests: XCTestCase { XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"]) } } + + 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") + } } class PayloadTests: XCTestCase { From ec727f11324b7d2936aad8c22ff19a0649cb3fe6 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 3 Aug 2017 18:04:28 -0700 Subject: [PATCH 066/127] feat: Support conditional CommonCrypto --- JSONWebToken.podspec | 1 + JWT.xcodeproj/project.pbxproj | 22 ++++++++++++++++ Package.swift | 3 ++- Sources/HMAC.swift | 7 ++++++ Sources/HMACCommonCrypto.swift | 46 ++++++++++++++++++++++++++++++++++ Sources/HMACCryptoSwift.swift | 28 +++++++++++++++++++++ Sources/JWT.swift | 18 ++++--------- 7 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 Sources/HMAC.swift create mode 100644 Sources/HMACCommonCrypto.swift create mode 100644 Sources/HMACCryptoSwift.swift diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 2bf5306..fd86d92 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -14,4 +14,5 @@ Pod::Spec.new do |spec| spec.requires_arc = true spec.dependency 'CryptoSwift', '~> 0.6.1' spec.module_name = 'JWT' + spec.exclude_files = ['Sources/HMACCommonCrypto.swift'] end diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 4158229..eb97184 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -7,6 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; + 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; + 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; + 273011021F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; + 2730110A1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; + 2730110B1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; + 2730110C1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; + 2730110D1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; 2734C6A81D88001F00BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; 2734C6A91D88002900BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; 2734C6AA1D88003000BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; @@ -79,6 +87,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; + 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; + 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; 277794041DF221F800573F3E /* ClaimSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClaimSet.swift; sourceTree = ""; }; 2777940A1DF22BE400573F3E /* JOSEHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JOSEHeader.swift; sourceTree = ""; }; 2777940F1DF22D0D00573F3E /* Encode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Encode.swift; sourceTree = ""; }; @@ -218,6 +229,9 @@ 520A71151C469F010005C709 /* Decode.swift */, 2777940F1DF22D0D00573F3E /* Encode.swift */, 520A71161C469F010005C709 /* JWT.swift */, + 273010FE1F33EABA00219C35 /* HMAC.swift */, + 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */, + 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */, ); path = Sources; sourceTree = ""; @@ -481,7 +495,9 @@ 277794101DF22D0D00573F3E /* Encode.swift in Sources */, 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, + 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */, 520A71171C469F010005C709 /* Base64.swift in Sources */, + 2730110A1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -503,7 +519,9 @@ 277794111DF22D0D00573F3E /* Encode.swift in Sources */, 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, + 273011001F33EABA00219C35 /* HMAC.swift in Sources */, CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, + 2730110B1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -517,7 +535,9 @@ 277794121DF22D0D00573F3E /* Encode.swift in Sources */, 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, + 273011011F33EABA00219C35 /* HMAC.swift in Sources */, CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, + 2730110C1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -531,7 +551,9 @@ 277794131DF22D0D00573F3E /* Encode.swift in Sources */, 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, + 273011021F33EABA00219C35 /* HMAC.swift in Sources */, CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, + 2730110D1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Package.swift b/Package.swift index f90189c..e6f794a 100644 --- a/Package.swift +++ b/Package.swift @@ -4,5 +4,6 @@ let package = Package( name: "JWT", dependencies: [ .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0, 6, 1) ..< Version(0, 7, 0)), - ] + ], + exclude: ["Sources/HMACCommonCrypto.swift"] ) diff --git a/Sources/HMAC.swift b/Sources/HMAC.swift new file mode 100644 index 0000000..2e9c66a --- /dev/null +++ b/Sources/HMAC.swift @@ -0,0 +1,7 @@ +import Foundation + +enum HMACAlgorithm { + case sha256 + case sha384 + case sha512 +} diff --git a/Sources/HMACCommonCrypto.swift b/Sources/HMACCommonCrypto.swift new file mode 100644 index 0000000..a144ccb --- /dev/null +++ b/Sources/HMACCommonCrypto.swift @@ -0,0 +1,46 @@ +import Foundation +import CommonCrypto + + +extension HMACAlgorithm { + var commonCryptoAlgorithm: CCHmacAlgorithm { + switch self { + case .sha256: + return CCHmacAlgorithm(kCCHmacAlgSHA256) + case .sha384: + return CCHmacAlgorithm(kCCHmacAlgSHA384) + case .sha512: + return CCHmacAlgorithm(kCCHmacAlgSHA512) + } + } + + var commonCryptoDigestLength: Int32 { + switch self { + case .sha256: + return CC_SHA256_DIGEST_LENGTH + case .sha384: + return CC_SHA384_DIGEST_LENGTH + case .sha512: + return CC_SHA512_DIGEST_LENGTH + } + } +} + + +func hmac(algorithm: HMACAlgorithm, key: Data, message: Data) -> Data { + let context = UnsafeMutablePointer.allocate(capacity: 1) + defer { context.deallocate(capacity: 1) } + + key.withUnsafeBytes() { (buffer: UnsafePointer) in + CCHmacInit(context, algorithm.commonCryptoAlgorithm, buffer, size_t(key.count)) + } + + message.withUnsafeBytes { (buffer: UnsafePointer) in + CCHmacUpdate(context, buffer, size_t(message.count)) + } + + var hmac = Array(repeating: 0, count: Int(algorithm.commonCryptoDigestLength)) + CCHmacFinal(context, &hmac) + + return Data(hmac) +} diff --git a/Sources/HMACCryptoSwift.swift b/Sources/HMACCryptoSwift.swift new file mode 100644 index 0000000..401a803 --- /dev/null +++ b/Sources/HMACCryptoSwift.swift @@ -0,0 +1,28 @@ +import Foundation +import CryptoSwift + + +extension HMACAlgorithm { + var cryptoSwiftVariant: HMAC.Variant { + switch self { + case .sha256: + return .sha256 + case .sha384: + return .sha384 + case .sha512: + return .sha512 + } + } +} + + +func hmac(algorithm: HMACAlgorithm, key: Data, message: Data) -> Data { + let mac = HMAC(key: key.bytes, variant: algorithm.cryptoSwiftVariant) + let result: [UInt8] + do { + result = try mac.authenticate(message.bytes) + } catch { + result = [] + } + return Data(bytes: result) +} diff --git a/Sources/JWT.swift b/Sources/JWT.swift index 3b3e4a3..b412da3 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -1,5 +1,4 @@ import Foundation -import CryptoSwift public typealias Payload = [String: Any] @@ -32,16 +31,9 @@ public enum Algorithm: CustomStringConvertible { /// Sign a message using the algorithm func sign(_ message: String) -> String { - func signHS(_ key: Data, variant: CryptoSwift.HMAC.Variant) -> String { + func signHS(_ key: Data, algorithm: HMACAlgorithm) -> String { let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! - let mac = HMAC(key: key.bytes, variant: variant) - let result: [UInt8] - do { - result = try mac.authenticate(messageData.bytes) - } catch { - result = [] - } - return base64encode(Data(bytes: result)) + return base64encode(hmac(algorithm: algorithm, key: key, message: messageData)) } switch self { @@ -49,13 +41,13 @@ public enum Algorithm: CustomStringConvertible { return "" case .hs256(let key): - return signHS(key, variant: .sha256) + return signHS(key, algorithm: .sha256) case .hs384(let key): - return signHS(key, variant: .sha384) + return signHS(key, algorithm: .sha384) case .hs512(let key): - return signHS(key, variant: .sha512) + return signHS(key, algorithm: .sha512) } } From 7451fcfaeb4dfc56403570f759e6bf3290db0f7c Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 4 Aug 2017 09:01:50 -0700 Subject: [PATCH 067/127] feat: Use CommonCrypto on Apple platforms for SwiftPM --- Package.swift | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index e6f794a..7e6ad13 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,24 @@ import PackageDescription + +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +let package = Package( + name: "JWT", + dependencies: [ + .Package(url: "https://github.com/kylef-archive/CommonCrypto.git", majorVersion: 1), + ], + exclude: [ + "Sources/HMACCryptoSwift.swift", + ] +) +#else let package = Package( name: "JWT", dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", versions: Version(0, 6, 1) ..< Version(0, 7, 0)), + .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", majorVersion: 0, minor: 6), ], - exclude: ["Sources/HMACCommonCrypto.swift"] + exclude: [ + "Sources/HMACCommonCrypto.swift", + ] ) +#endif From 558eaf1ca7ac41ae11747c4c3d4057997d93913f Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 4 Aug 2017 10:14:45 -0700 Subject: [PATCH 068/127] fix(Package): Add `.git` extension to CryptoSwift Fixes #63 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 7e6ad13..eb6f28b 100644 --- a/Package.swift +++ b/Package.swift @@ -15,7 +15,7 @@ let package = Package( let package = Package( name: "JWT", dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift", majorVersion: 0, minor: 6), + .Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0, minor: 6), ], exclude: [ "Sources/HMACCommonCrypto.swift", From fcf2f1286ff9b59d21995e5940aac5f157b15f27 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 4 Aug 2017 09:18:35 -0700 Subject: [PATCH 069/127] feat: Use CommonCrypto in JWT Pod --- CommonCrypto/module.modulemap | 4 ++++ CommonCrypto/shim.h | 1 + JSONWebToken.podspec | 15 +++++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 CommonCrypto/module.modulemap create mode 100644 CommonCrypto/shim.h diff --git a/CommonCrypto/module.modulemap b/CommonCrypto/module.modulemap new file mode 100644 index 0000000..b70f7d6 --- /dev/null +++ b/CommonCrypto/module.modulemap @@ -0,0 +1,4 @@ +module CommonCrypto [system] { + header "shim.h" + export * +} diff --git a/CommonCrypto/shim.h b/CommonCrypto/shim.h new file mode 100644 index 0000000..c332624 --- /dev/null +++ b/CommonCrypto/shim.h @@ -0,0 +1 @@ +#include diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index fd86d92..42698f6 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -12,7 +12,18 @@ Pod::Spec.new do |spec| spec.tvos.deployment_target = '9.0' spec.watchos.deployment_target = '2.0' spec.requires_arc = true - spec.dependency 'CryptoSwift', '~> 0.6.1' spec.module_name = 'JWT' - spec.exclude_files = ['Sources/HMACCommonCrypto.swift'] + spec.exclude_files = ['Sources/HMACCryptoSwift.swift'] + + if ARGV.include?('lint') + spec.pod_target_xcconfig = { + 'SWIFT_INCLUDE_PATHS' => Dir.pwd, + } + else + spec.pod_target_xcconfig = { + 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/JSONWebToken/', + } + end + + spec.preserve_paths = 'CommonCrypto/{shim.h,module.modulemap}' end From aee8d905f5b6def05517466289345f8f827be75b Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 4 Aug 2017 09:17:07 -0700 Subject: [PATCH 070/127] feat: Use CommonCrypto in Xcode --- .gitmodules | 3 -- Cartfile | 1 - Cartfile.resolved | 1 - Carthage/Checkouts/CryptoSwift | 1 - JWT.xcodeproj/project.pbxproj | 85 ++++------------------------------ 5 files changed, 8 insertions(+), 83 deletions(-) delete mode 100644 .gitmodules delete mode 100644 Cartfile delete mode 100644 Cartfile.resolved delete mode 160000 Carthage/Checkouts/CryptoSwift diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 761522b..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "Carthage/Checkouts/CryptoSwift"] - path = Carthage/Checkouts/CryptoSwift - url = https://github.com/krzyzanowskim/CryptoSwift.git diff --git a/Cartfile b/Cartfile deleted file mode 100644 index 4f0cac5..0000000 --- a/Cartfile +++ /dev/null @@ -1 +0,0 @@ -github "krzyzanowskim/CryptoSwift" ~> 0.6.1 diff --git a/Cartfile.resolved b/Cartfile.resolved deleted file mode 100644 index 5b562e4..0000000 --- a/Cartfile.resolved +++ /dev/null @@ -1 +0,0 @@ -github "krzyzanowskim/CryptoSwift" "0.6.1" diff --git a/Carthage/Checkouts/CryptoSwift b/Carthage/Checkouts/CryptoSwift deleted file mode 160000 index 5f9bb95..0000000 --- a/Carthage/Checkouts/CryptoSwift +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5f9bb95c6f246c7e19bf4346a6ad1a0c406415f0 diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index eb97184..6fc3a21 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -11,13 +11,10 @@ 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011021F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; - 2730110A1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; - 2730110B1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; - 2730110C1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; - 2730110D1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */; }; - 2734C6A81D88001F00BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; - 2734C6A91D88002900BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; - 2734C6AA1D88003000BFF9F1 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; + 273011161F34029900219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; + 273011171F34029900219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; + 273011181F34029A00219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; + 273011191F34029A00219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; 277794051DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; 277794061DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; 277794071DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; @@ -52,7 +49,6 @@ CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; CD9B62421C7753FB005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CD9B62891C7758BB005D4844 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -63,27 +59,6 @@ remoteGlobalIDString = 279D639B1AD07FFF0024E2BC; remoteInfo = JWT; }; - 66725DAA1C59202E00FC32F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 754BE45519693E190098E6F3; - remoteInfo = "CryptoSwift iOS"; - }; - 66725DB21C59202E00FC32F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 754BE46019693E190098E6F3; - remoteInfo = CryptoSwiftTests; - }; - CD9B628A1C7758CA005D4844 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 754BE45419693E190098E6F3; - remoteInfo = "CryptoSwift iOS"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -105,7 +80,6 @@ 520A71161C469F010005C709 /* JWT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; 520A711B1C469F440005C709 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 540942F3614C41E3827F2013 /* Pods_JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CryptoSwift.xcodeproj; path = Carthage/Checkouts/CryptoSwift/CryptoSwift.xcodeproj; sourceTree = ""; }; CD9B62231C7753D8005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CD9B62351C7753EC005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CD9B62471C7753FB005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -117,7 +91,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2734C6A81D88001F00BFF9F1 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -133,7 +106,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CD9B62891C7758BB005D4844 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -141,7 +113,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2734C6A91D88002900BFF9F1 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -149,7 +120,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2734C6AA1D88003000BFF9F1 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -159,7 +129,6 @@ 279D63921AD07FFF0024E2BC = { isa = PBXGroup; children = ( - 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */, 520A711B1C469F440005C709 /* Package.swift */, 520A71121C469F010005C709 /* Sources */, 279D639E1AD07FFF0024E2BC /* Sources */, @@ -236,15 +205,6 @@ path = Sources; sourceTree = ""; }; - 66725DA31C59202E00FC32F4 /* Products */ = { - isa = PBXGroup; - children = ( - 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */, - 66725DB31C59202E00FC32F4 /* Tests.xctest */, - ); - name = Products; - sourceTree = ""; - }; AC8AE547FDAF3DD80EB4DB2F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -340,7 +300,6 @@ buildRules = ( ); dependencies = ( - CD9B628B1C7758CA005D4844 /* PBXTargetDependency */, ); name = "JWT-iOS"; productName = JWT; @@ -412,12 +371,6 @@ mainGroup = 279D63921AD07FFF0024E2BC; productRefGroup = 279D639D1AD07FFF0024E2BC /* Products */; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 66725DA31C59202E00FC32F4 /* Products */; - ProjectRef = 66725DA21C59202E00FC32F4 /* CryptoSwift.xcodeproj */; - }, - ); projectRoot = ""; targets = ( 279D639B1AD07FFF0024E2BC /* JWT-OSX */, @@ -429,23 +382,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - 66725DAB1C59202E00FC32F4 /* CryptoSwift.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CryptoSwift.framework; - remoteRef = 66725DAA1C59202E00FC32F4 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 66725DB31C59202E00FC32F4 /* Tests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = Tests.xctest; - remoteRef = 66725DB21C59202E00FC32F4 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ 279D63A51AD07FFF0024E2BC /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -489,6 +425,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 273011161F34029900219C35 /* HMACCommonCrypto.swift in Sources */, 520A71181C469F010005C709 /* Claims.swift in Sources */, 520A711A1C469F010005C709 /* JWT.swift in Sources */, 520A71191C469F010005C709 /* Decode.swift in Sources */, @@ -497,7 +434,6 @@ 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */, 520A71171C469F010005C709 /* Base64.swift in Sources */, - 2730110A1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -513,6 +449,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 273011171F34029900219C35 /* HMACCommonCrypto.swift in Sources */, CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, @@ -521,7 +458,6 @@ 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, 273011001F33EABA00219C35 /* HMAC.swift in Sources */, CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, - 2730110B1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -529,6 +465,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 273011181F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, @@ -537,7 +474,6 @@ 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, 273011011F33EABA00219C35 /* HMAC.swift in Sources */, CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, - 2730110C1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -545,6 +481,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 273011191F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, @@ -553,7 +490,6 @@ 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, 273011021F33EABA00219C35 /* HMAC.swift in Sources */, CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, - 2730110D1F33FC9100219C35 /* HMACCryptoSwift.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -565,11 +501,6 @@ target = 279D639B1AD07FFF0024E2BC /* JWT-OSX */; targetProxy = 279D63A91AD07FFF0024E2BC /* PBXContainerItemProxy */; }; - CD9B628B1C7758CA005D4844 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "CryptoSwift iOS"; - targetProxy = CD9B628A1C7758CA005D4844 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ From 9b7463fa6485f2e708049cc058d9571486b51c0a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 4 Aug 2017 11:41:47 -0700 Subject: [PATCH 071/127] fix: Allow Xcode to find CommonCrypto --- JWT.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 6fc3a21..b2cc594 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -547,6 +547,7 @@ ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; @@ -590,6 +591,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; From 716873a23681e84b69833ff79d07f15e78ea0b6c Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Thu, 7 Sep 2017 16:39:48 +0200 Subject: [PATCH 072/127] Added leeway for date validation issue #54 --- Sources/ClaimSet.swift | 22 +++++++++++----------- Sources/Claims.swift | 6 +++--- Sources/Decode.swift | 8 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Sources/ClaimSet.swift b/Sources/ClaimSet.swift index 7626498..3632bc2 100644 --- a/Sources/ClaimSet.swift +++ b/Sources/ClaimSet.swift @@ -93,7 +93,7 @@ extension ClaimSet { // MARK: Validations extension ClaimSet { - public func validate(audience: String? = nil, issuer: String? = nil) throws { + public func validate(audience: String? = nil, issuer: String? = nil, leeway: TimeInterval = 0) throws { if let issuer = issuer { try validateIssuer(issuer) } @@ -101,10 +101,10 @@ extension ClaimSet { if let audience = audience { try validateAudience(audience) } - - try validateExpiary() - try validateNotBefore() - try validateIssuedAt() + + try validateExpiary(leeway: leeway) + try validateNotBefore(leeway: leeway) + try validateIssuedAt(leeway: leeway) } public func validateAudience(_ audience: String) throws { @@ -131,16 +131,16 @@ extension ClaimSet { } } - public func validateExpiary() throws { - try validateDate(claims, key: "exp", comparison: .orderedAscending, failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer") + public func validateExpiary(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") } - public func validateNotBefore() throws { - try validateDate(claims, key: "nbf", comparison: .orderedDescending, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") + public func validateNotBefore(leeway: TimeInterval = 0) throws { + try validateDate(claims, key: "nbf", comparison: .orderedDescending, leeway: leeway, failure: .immatureSignature, decodeError: "Not before claim (nbf) must be an integer") } - public func validateIssuedAt() throws { - try validateDate(claims, key: "iat", comparison: .orderedDescending, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") + public func validateIssuedAt(leeway: TimeInterval = 0) throws { + try validateDate(claims, key: "iat", comparison: .orderedDescending, leeway: leeway, failure: .invalidIssuedAt, decodeError: "Issued at claim (iat) must be an integer") } } diff --git a/Sources/Claims.swift b/Sources/Claims.swift index ad07027..d1df6f4 100644 --- a/Sources/Claims.swift +++ b/Sources/Claims.swift @@ -1,6 +1,6 @@ import Foundation -func validateDate(_ payload: Payload, key: String, comparison: ComparisonResult, failure: InvalidToken, decodeError: String) throws { +func validateDate(_ payload: Payload, key: String, comparison: ComparisonResult, leeway: TimeInterval = 0, failure: InvalidToken, decodeError: String) throws { if payload[key] == nil { return } @@ -8,8 +8,8 @@ func validateDate(_ payload: Payload, key: String, comparison: ComparisonResult, guard let date = extractDate(payload: payload, key: key) else { throw InvalidToken.decodeError(decodeError) } - - if date.compare(Date()) == comparison { + + if date.compare(Date().addingTimeInterval(leeway)) == comparison { throw failure } } diff --git a/Sources/Decode.swift b/Sources/Decode.swift index ce802d7..3e7ca41 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -47,11 +47,11 @@ public enum InvalidToken: CustomStringConvertible, Error { /// Decode a JWT -public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { +public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil, leeway: TimeInterval = 0) throws -> ClaimSet { let (header, claims, signature, signatureInput) = try load(jwt) if verify { - try claims.validate(audience: audience, issuer: issuer) + try claims.validate(audience: audience, issuer: issuer, leeway: leeway) try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) } @@ -59,8 +59,8 @@ public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, } /// Decode a JWT -public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> ClaimSet { - return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer) +public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil, leeway: TimeInterval = 0) throws -> ClaimSet { + return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer, leeway: leeway) } /// Decode a JWT From 803fcea3b1b150b66dc08f7eaea624a7c4b48bed Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Thu, 7 Sep 2017 16:40:12 +0200 Subject: [PATCH 073/127] Added unit tests for date validation with leeway. --- Tests/JWTTests/JWTTests.swift | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index a0e1b8f..2659230 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -279,6 +279,89 @@ class DecodeTests: XCTestCase { } } +class ValidationTests: XCTestCase { + func testClaimJustExpiredWithoutLeeway() { + var claims = ClaimSet() + claims.expiration = Date().addingTimeInterval(-1) + + let expectation = XCTestExpectation(description: "Signature should be expired.") + do { + try claims.validateExpiary() + XCTFail("InvalidToken.expiredSignature error should have been thrown.") + } catch InvalidToken.expiredSignature { + expectation.fulfill() + } catch { + XCTFail("Unexpected error while validating exp claim.") + } + self.wait(for: [expectation], timeout: 0.5) + } + + func testClaimJustNotExpiredWithoutLeeway() { + var claims = ClaimSet() + claims.expiration = Date().addingTimeInterval(-1) + + do { + try claims.validateExpiary(leeway: 2) + } catch { + XCTFail("Unexpected error while validating exp claim that should be valid with leeway.") + } + } + + func testNotBeforeIsImmatureSignatureWithoutLeeway() { + var claims = ClaimSet() + claims.notBefore = Date().addingTimeInterval(1) + + let expectation = XCTestExpectation(description: "Signature should be immature.") + do { + try claims.validateNotBefore() + XCTFail("InvalidToken.immatureSignature error should have been thrown.") + } catch InvalidToken.immatureSignature { + expectation.fulfill() + } catch { + XCTFail("Unexpected error while validating nbf claim.") + } + self.wait(for: [expectation], timeout: 0.5) + } + + func testNotBeforeIsValidWithLeeway() { + var claims = ClaimSet() + claims.notBefore = Date().addingTimeInterval(1) + + do { + try claims.validateNotBefore(leeway: 2) + } catch { + XCTFail("Unexpected error while validating nbf claim that should be valid with leeway.") + } + } + + func testIssuedAtIsInFutureWithoutLeeway() { + var claims = ClaimSet() + claims.issuedAt = Date().addingTimeInterval(1) + + let expectation = XCTestExpectation(description: "iat should be in the future.") + do { + try claims.validateIssuedAt() + XCTFail("InvalidToken.invalidIssuedAt error should have been thrown.") + } catch InvalidToken.invalidIssuedAt { + expectation.fulfill() + } catch { + XCTFail("Unexpected error while validating iat claim.") + } + self.wait(for: [expectation], timeout: 0.5) + } + + func testIssuedAtIsValidWithLeeway() { + var claims = ClaimSet() + claims.issuedAt = Date().addingTimeInterval(1) + + do { + try claims.validateIssuedAt(leeway: 2) + } catch { + XCTFail("Unexpected error while validating iat claim that should be valid with leeway.") + } + } +} + // MARK: Helpers func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure: ((Payload) -> Void)? = nil) { From 78dc2010cf00a7d3c9bfcddacd554bf6096697aa Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Thu, 7 Sep 2017 16:40:34 +0200 Subject: [PATCH 074/127] Added some integration tests for verification of dates with and without leeway. --- Tests/JWTTests/JWTTests.swift | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 2659230..4c1e8a9 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -362,6 +362,46 @@ class ValidationTests: XCTestCase { } } +class IntegrationTests: XCTestCase { + func testVerificationFailureWithoutLeeway() { + let token = JWT.encode(.none) { builder in + builder.issuer = "fuller.li" + builder.audience = "cocoapods" + builder.expiration = Date().addingTimeInterval(-1) // Token expired one second ago + builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second + builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future + } + + let expectation = XCTestExpectation(description: "Verification should fail.") + do { + let _ = try JWT.decode(token, algorithm: .none) + XCTFail("InvalidToken error should have been thrown.") + } catch is InvalidToken { + expectation.fulfill() + } catch { + XCTFail("Unexpected error type while verifying token.") + } + self.wait(for: [expectation], timeout: 0.5) + } + + func testVerificationSuccessWithLeeway() { + let token = JWT.encode(.none) { builder in + builder.issuer = "fuller.li" + builder.audience = "cocoapods" + builder.expiration = Date().addingTimeInterval(-1) // Token expired one second ago + builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second + builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future + } + + do { + let _ = try JWT.decode(token, algorithm: .none, leeway: 2) + // Due to leeway no error gets thrown. + } catch { + XCTFail("Unexpected error type while verifying token.") + } + } +} + // MARK: Helpers func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure: ((Payload) -> Void)? = nil) { From 0a3e73538185a0db5bc52d7ea339134384bc91c1 Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Thu, 7 Sep 2017 16:46:43 +0200 Subject: [PATCH 075/127] Repaired indentation mix of spaces and tabs. --- Sources/ClaimSet.swift | 4 ++-- Sources/Decode.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/ClaimSet.swift b/Sources/ClaimSet.swift index 3632bc2..7dcf872 100644 --- a/Sources/ClaimSet.swift +++ b/Sources/ClaimSet.swift @@ -131,8 +131,8 @@ extension ClaimSet { } } - public func validateExpiary(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") + public func validateExpiary(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") } public func validateNotBefore(leeway: TimeInterval = 0) throws { diff --git a/Sources/Decode.swift b/Sources/Decode.swift index 3e7ca41..3054160 100644 --- a/Sources/Decode.swift +++ b/Sources/Decode.swift @@ -51,7 +51,7 @@ public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, let (header, claims, signature, signatureInput) = try load(jwt) if verify { - try claims.validate(audience: audience, issuer: issuer, leeway: leeway) + try claims.validate(audience: audience, issuer: issuer, leeway: leeway) try verifySignature(algorithms, header: header, signingInput: signatureInput, signature: signature) } @@ -60,7 +60,7 @@ public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, /// Decode a JWT public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil, leeway: TimeInterval = 0) throws -> ClaimSet { - return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer, leeway: leeway) + return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer, leeway: leeway) } /// Decode a JWT From 5f6907e46f097f7726cd4e82a43a87b6817da5b8 Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Fri, 8 Sep 2017 09:46:26 +0200 Subject: [PATCH 076/127] Fixing unit test build error on Linux. --- Tests/JWTTests/JWTTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 4c1e8a9..337b664 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -374,7 +374,7 @@ class IntegrationTests: XCTestCase { let expectation = XCTestExpectation(description: "Verification should fail.") do { - let _ = try JWT.decode(token, algorithm: .none) + let _ = try JWT.decode(token, algorithm: .none, leeway: 0) XCTFail("InvalidToken error should have been thrown.") } catch is InvalidToken { expectation.fulfill() From 6affa9356f1542124f288fedf0186dd35a4dcebc Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Fri, 8 Sep 2017 12:54:01 +0200 Subject: [PATCH 077/127] Removed XCTestExpectations from validation tests. --- Tests/JWTTests/JWTTests.swift | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 337b664..b8ffe50 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -283,17 +283,15 @@ class ValidationTests: XCTestCase { func testClaimJustExpiredWithoutLeeway() { var claims = ClaimSet() claims.expiration = Date().addingTimeInterval(-1) - - let expectation = XCTestExpectation(description: "Signature should be expired.") + do { try claims.validateExpiary() XCTFail("InvalidToken.expiredSignature error should have been thrown.") } catch InvalidToken.expiredSignature { - expectation.fulfill() + // Correct error thrown } catch { XCTFail("Unexpected error while validating exp claim.") } - self.wait(for: [expectation], timeout: 0.5) } func testClaimJustNotExpiredWithoutLeeway() { @@ -311,16 +309,14 @@ class ValidationTests: XCTestCase { var claims = ClaimSet() claims.notBefore = Date().addingTimeInterval(1) - let expectation = XCTestExpectation(description: "Signature should be immature.") do { try claims.validateNotBefore() XCTFail("InvalidToken.immatureSignature error should have been thrown.") } catch InvalidToken.immatureSignature { - expectation.fulfill() + // Correct error thrown } catch { XCTFail("Unexpected error while validating nbf claim.") } - self.wait(for: [expectation], timeout: 0.5) } func testNotBeforeIsValidWithLeeway() { @@ -337,17 +333,15 @@ class ValidationTests: XCTestCase { func testIssuedAtIsInFutureWithoutLeeway() { var claims = ClaimSet() claims.issuedAt = Date().addingTimeInterval(1) - - let expectation = XCTestExpectation(description: "iat should be in the future.") + do { try claims.validateIssuedAt() XCTFail("InvalidToken.invalidIssuedAt error should have been thrown.") } catch InvalidToken.invalidIssuedAt { - expectation.fulfill() + // Correct error thrown } catch { XCTFail("Unexpected error while validating iat claim.") } - self.wait(for: [expectation], timeout: 0.5) } func testIssuedAtIsValidWithLeeway() { @@ -371,17 +365,15 @@ class IntegrationTests: XCTestCase { builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future } - - let expectation = XCTestExpectation(description: "Verification should fail.") + do { let _ = try JWT.decode(token, algorithm: .none, leeway: 0) XCTFail("InvalidToken error should have been thrown.") } catch is InvalidToken { - expectation.fulfill() + // Correct error thrown } catch { XCTFail("Unexpected error type while verifying token.") } - self.wait(for: [expectation], timeout: 0.5) } func testVerificationSuccessWithLeeway() { From fef37501a783709a7cc52fb8b4523a46de9844ae Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Mon, 11 Sep 2017 14:40:54 +0200 Subject: [PATCH 078/127] Added leeway parameter introduction to changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd856eb..9588b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Enhancements - Allow passing additional headers when encoding a JWT. +- Allow passing leeway parameter for date checks when verifying a JWT. ## 2.1.0 From a6fa6d8df6b391868710f495684557426cd187db Mon Sep 17 00:00:00 2001 From: Jan Brinker Date: Mon, 11 Sep 2017 14:42:20 +0200 Subject: [PATCH 079/127] Added documentation for leeway parameter for decoding. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 830f70d..9a6fae2 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,12 @@ try JWT.decode("eyJh...5w", algorithms: [ ]) ``` +You might also want to give your iat, exp and nbf checks some kind of leeway to account for skewed clocks. You can do this by passing a `leeway` parameter like this: + +```swift +try JWT.decode("eyJh...5w", algorithm: .hs256("secret".data(using: .utf8)!), leeway: 10) +``` + #### Supported claims The library supports validating the following claims: From e5745f95a3e60d9ccee4900764ec79b4239c4ef9 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 20 Sep 2017 01:33:34 +0100 Subject: [PATCH 080/127] chore: Release 2.2.0 --- CHANGELOG.md | 3 ++- JSONWebToken.podspec | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9588b8f..2b9686c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # JSON Web Token Changelog -## Master +## 2.2.0 ### Enhancements +- On Apple platforms, JSONWebToken will use the system CommonCrypto where possible. - Allow passing additional headers when encoding a JWT. - Allow passing leeway parameter for date checks when verifying a JWT. diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 42698f6..f17fd79 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'JSONWebToken' - spec.version = '2.1.1' + spec.version = '2.2.0' spec.summary = 'Swift library for JSON Web Tokens (JWT).' spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' spec.license = { :type => 'BSD', :file => 'LICENSE' } From 3c9b3a62d82050c875147ac51edb7aa2389d7013 Mon Sep 17 00:00:00 2001 From: Graham Chance Date: Tue, 26 Sep 2017 10:55:11 -0400 Subject: [PATCH 081/127] docs: typo in README (#87) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a6fae2..d864130 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ claims.issuer = "fuller.li" claims.issuedAt = Date() claims["custom"] = "Hi" -JWT.encode(claims: claims, algorithm, algorithm: .hs256("secret".data(using: .utf8))) +JWT.encode(claims: claims, algorithm: .hs256("secret".data(using: .utf8))) ``` #### Building a JWT with the builder pattern From 5c5607b2a68ce8264201296b8bcdb4dccfb77617 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 28 Sep 2017 10:23:16 +0100 Subject: [PATCH 082/127] chore: Update to Xcode project defaults --- JWT.xcodeproj/project.pbxproj | 18 +++++++++++++++--- .../xcshareddata/xcschemes/JWT-OSX.xcscheme | 4 +++- .../xcshareddata/xcschemes/JWT-iOS.xcscheme | 4 +++- .../xcshareddata/xcschemes/JWT-tvOS.xcscheme | 4 +++- .../xcschemes/JWT-watchOS.xcscheme | 4 +++- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index b2cc594..4d053c4 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -350,7 +350,7 @@ attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0910; ORGANIZATIONNAME = Cocode; TargetAttributes = { 279D639B1AD07FFF0024E2BC = { @@ -512,14 +512,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -549,7 +555,7 @@ SDKROOT = macosx; SWIFT_INCLUDE_PATHS = "$(SRCROOT)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -563,14 +569,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -593,7 +605,7 @@ SDKROOT = macosx; SWIFT_INCLUDE_PATHS = "$(SRCROOT)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme index ff0db9d..dc61530 100644 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme index 624d99c..46efb5f 100644 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme index 87c365a..c0bf55d 100644 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme +++ b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme @@ -1,6 +1,6 @@ @@ -36,6 +37,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" From 81f55d391a41cd7ec8efcc4987dcde2342b53cad Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 3 Oct 2017 22:44:35 +0100 Subject: [PATCH 083/127] docs: Update recommended installation method(s) --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d864130..ce1db66 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ Swift implementation of [JSON Web Token](https://tools.ietf.org/html/draft-ietf- ## Installation -[CocoaPods](http://cocoapods.org/) is the recommended installation method. +Swift Pacakage Manager is the recommended installation method for JSONWebToken, [CocoaPods](http://cocoapods.org/) is also supported. ```ruby pod 'JSONWebToken' ``` +**NOTE:** *Carthage may be supported, however support will not be provided for this installation method, use at your own risk if you know how it works.* + ## Usage ```swift From ad8ed43d5fb83ea730c81f2b8e8517cbe4cbf7d4 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 00:33:52 +0200 Subject: [PATCH 084/127] refactor: Move JWA to separate file --- JWT.xcodeproj/project.pbxproj | 10 +++++++ Sources/JWA.swift | 55 +++++++++++++++++++++++++++++++++++ Sources/JWT.swift | 55 ----------------------------------- 3 files changed, 65 insertions(+), 55 deletions(-) create mode 100644 Sources/JWA.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 4d053c4..b0c461f 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 271E10801F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; + 271E10811F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; + 271E10821F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; + 271E10831F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; @@ -62,6 +66,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 271E107F1F90253300B5033C /* JWA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWA.swift; sourceTree = ""; }; 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; @@ -198,6 +203,7 @@ 520A71151C469F010005C709 /* Decode.swift */, 2777940F1DF22D0D00573F3E /* Encode.swift */, 520A71161C469F010005C709 /* JWT.swift */, + 271E107F1F90253300B5033C /* JWA.swift */, 273010FE1F33EABA00219C35 /* HMAC.swift */, 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */, 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */, @@ -425,6 +431,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 271E10801F90253300B5033C /* JWA.swift in Sources */, 273011161F34029900219C35 /* HMACCommonCrypto.swift in Sources */, 520A71181C469F010005C709 /* Claims.swift in Sources */, 520A711A1C469F010005C709 /* JWT.swift in Sources */, @@ -449,6 +456,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 271E10811F90253300B5033C /* JWA.swift in Sources */, 273011171F34029900219C35 /* HMACCommonCrypto.swift in Sources */, CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, @@ -465,6 +473,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 271E10821F90253300B5033C /* JWA.swift in Sources */, 273011181F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, @@ -481,6 +490,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 271E10831F90253300B5033C /* JWA.swift in Sources */, 273011191F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, diff --git a/Sources/JWA.swift b/Sources/JWA.swift new file mode 100644 index 0000000..950b1b1 --- /dev/null +++ b/Sources/JWA.swift @@ -0,0 +1,55 @@ +/// Represents a JSON Web Algorithm (JWA) +/// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 +public enum Algorithm: CustomStringConvertible { + /// No Algorithm, i-e, insecure + case none + + /// HMAC using SHA-256 hash algorithm + case hs256(Data) + + /// HMAC using SHA-384 hash algorithm + case hs384(Data) + + /// HMAC using SHA-512 hash algorithm + case hs512(Data) + + public var description: String { + switch self { + case .none: + return "none" + case .hs256: + return "HS256" + case .hs384: + return "HS384" + case .hs512: + return "HS512" + } + } + + /// Sign a message using the algorithm + func sign(_ message: String) -> String { + func signHS(_ key: Data, algorithm: HMACAlgorithm) -> String { + let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! + return base64encode(hmac(algorithm: algorithm, key: key, message: messageData)) + } + + switch self { + case .none: + return "" + + case .hs256(let key): + return signHS(key, algorithm: .sha256) + + case .hs384(let key): + return signHS(key, algorithm: .sha384) + + case .hs512(let key): + return signHS(key, algorithm: .sha512) + } + } + + /// Verify a signature for a message using the algorithm + func verify(_ message: String, signature: Data) -> Bool { + return sign(message) == base64encode(signature) + } +} diff --git a/Sources/JWT.swift b/Sources/JWT.swift index b412da3..5e5569e 100644 --- a/Sources/JWT.swift +++ b/Sources/JWT.swift @@ -1,58 +1,3 @@ import Foundation public typealias Payload = [String: Any] - -/// The supported Algorithms -public enum Algorithm: CustomStringConvertible { - /// No Algorithm, i-e, insecure - case none - - /// HMAC using SHA-256 hash algorithm - case hs256(Data) - - /// HMAC using SHA-384 hash algorithm - case hs384(Data) - - /// HMAC using SHA-512 hash algorithm - case hs512(Data) - - public var description: String { - switch self { - case .none: - return "none" - case .hs256: - return "HS256" - case .hs384: - return "HS384" - case .hs512: - return "HS512" - } - } - - /// Sign a message using the algorithm - func sign(_ message: String) -> String { - func signHS(_ key: Data, algorithm: HMACAlgorithm) -> String { - let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! - return base64encode(hmac(algorithm: algorithm, key: key, message: messageData)) - } - - switch self { - case .none: - return "" - - case .hs256(let key): - return signHS(key, algorithm: .sha256) - - case .hs384(let key): - return signHS(key, algorithm: .sha384) - - case .hs512(let key): - return signHS(key, algorithm: .sha512) - } - } - - /// Verify a signature for a message using the algorithm - func verify(_ message: String, signature: Data) -> Bool { - return sign(message) == base64encode(signature) - } -} From b20ecac938bcf48d7574ab57e74c802de78fb52a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 00:46:58 +0200 Subject: [PATCH 085/127] refactor: Add `type` property to JOSEHeader --- JWT.xcodeproj/project.pbxproj | 4 +++ Sources/JOSEHeader.swift | 10 +++++++ Tests/JWTTests/JOSEHeaderTests.swift | 42 ++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Tests/JWTTests/JOSEHeaderTests.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index b0c461f..52fba4c 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 271E10811F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 271E10821F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 271E10831F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; + 271E10851F90274A00B5033C /* JOSEHeaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */; }; 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; @@ -67,6 +68,7 @@ /* Begin PBXFileReference section */ 271E107F1F90253300B5033C /* JWA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWA.swift; sourceTree = ""; }; + 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JOSEHeaderTests.swift; sourceTree = ""; }; 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; @@ -179,6 +181,7 @@ isa = PBXGroup; children = ( 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */, + 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */, 279D63AC1AD07FFF0024E2BC /* Supporting Files */, ); name = Tests; @@ -449,6 +452,7 @@ buildActionMask = 2147483647; files = ( 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */, + 271E10851F90274A00B5033C /* JOSEHeaderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/JOSEHeader.swift b/Sources/JOSEHeader.swift index e19453c..4bfcf49 100644 --- a/Sources/JOSEHeader.swift +++ b/Sources/JOSEHeader.swift @@ -25,4 +25,14 @@ struct JOSEHeader { parameters["alg"] = newValue } } + + var type: String? { + get { + return parameters["typ"] as? String + } + + set { + parameters["typ"] = newValue + } + } } diff --git a/Tests/JWTTests/JOSEHeaderTests.swift b/Tests/JWTTests/JOSEHeaderTests.swift new file mode 100644 index 0000000..44af163 --- /dev/null +++ b/Tests/JWTTests/JOSEHeaderTests.swift @@ -0,0 +1,42 @@ +import XCTest +@testable import JWT + +class JOSEHeaderTests: XCTestCase { + // MARK: Algorithm + + func testGettingUnsetAlgoritm() { + let header = JOSEHeader(parameters: [:]) + XCTAssertNil(header.algorithm) + } + + func testGettingAlgoritm() { + let header = JOSEHeader(parameters: ["alg": "none"]) + XCTAssertEqual(header.algorithm, "none") + } + + func testSettingAlgoritm() { + var header = JOSEHeader(parameters: [:]) + + header.algorithm = "none" + XCTAssertEqual(header.algorithm, "none") + } + + // MARK: Type + + func testGettingUnsetType() { + let header = JOSEHeader(parameters: [:]) + XCTAssertNil(header.type) + } + + func testGettingType() { + let header = JOSEHeader(parameters: ["typ": "JWT"]) + XCTAssertEqual(header.type, "JWT") + } + + func testSettingType() { + var header = JOSEHeader(parameters: [:]) + + header.type = "JWT" + XCTAssertEqual(header.type, "JWT") + } +} From 7be4e4620e0daff27953e85da0018bc96ef5a8dd Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 01:12:54 +0200 Subject: [PATCH 086/127] refactor: Move JWT sources to JWT module --- JSONWebToken.podspec | 4 ++-- JWT.xcodeproj/project.pbxproj | 30 +++++++++++++++--------- Package.swift | 4 ++-- Sources/{ => JWT}/Base64.swift | 0 Sources/{ => JWT}/ClaimSet.swift | 0 Sources/{ => JWT}/Claims.swift | 0 Sources/{ => JWT}/Decode.swift | 0 Sources/{ => JWT}/Encode.swift | 0 Sources/{ => JWT}/HMAC.swift | 0 Sources/{ => JWT}/HMACCommonCrypto.swift | 0 Sources/{ => JWT}/HMACCryptoSwift.swift | 0 Sources/{ => JWT}/JOSEHeader.swift | 0 Sources/{ => JWT}/JWA.swift | 2 ++ Sources/{ => JWT}/JWT.swift | 0 14 files changed, 25 insertions(+), 15 deletions(-) rename Sources/{ => JWT}/Base64.swift (100%) rename Sources/{ => JWT}/ClaimSet.swift (100%) rename Sources/{ => JWT}/Claims.swift (100%) rename Sources/{ => JWT}/Decode.swift (100%) rename Sources/{ => JWT}/Encode.swift (100%) rename Sources/{ => JWT}/HMAC.swift (100%) rename Sources/{ => JWT}/HMACCommonCrypto.swift (100%) rename Sources/{ => JWT}/HMACCryptoSwift.swift (100%) rename Sources/{ => JWT}/JOSEHeader.swift (100%) rename Sources/{ => JWT}/JWA.swift (98%) rename Sources/{ => JWT}/JWT.swift (100%) diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index f17fd79..3ce74ef 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -6,14 +6,14 @@ Pod::Spec.new do |spec| spec.license = { :type => 'BSD', :file => 'LICENSE' } spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git', :tag => "#{spec.version}" } - spec.source_files = 'Sources/*.swift' + spec.source_files = 'Sources/JWT/*.swift' spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.tvos.deployment_target = '9.0' spec.watchos.deployment_target = '2.0' spec.requires_arc = true spec.module_name = 'JWT' - spec.exclude_files = ['Sources/HMACCryptoSwift.swift'] + spec.exclude_files = ['Sources/JWT/HMACCryptoSwift.swift'] if ARGV.include?('lint') spec.pod_target_xcconfig = { diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 52fba4c..3562610 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -133,6 +133,24 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 271E10861F902D8900B5033C /* JWT */ = { + isa = PBXGroup; + children = ( + 277794041DF221F800573F3E /* ClaimSet.swift */, + 2777940A1DF22BE400573F3E /* JOSEHeader.swift */, + 520A71131C469F010005C709 /* Base64.swift */, + 520A71141C469F010005C709 /* Claims.swift */, + 520A71151C469F010005C709 /* Decode.swift */, + 2777940F1DF22D0D00573F3E /* Encode.swift */, + 520A71161C469F010005C709 /* JWT.swift */, + 271E107F1F90253300B5033C /* JWA.swift */, + 273010FE1F33EABA00219C35 /* HMAC.swift */, + 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */, + 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */, + ); + path = JWT; + sourceTree = ""; + }; 279D63921AD07FFF0024E2BC = { isa = PBXGroup; children = ( @@ -199,17 +217,7 @@ 520A71121C469F010005C709 /* Sources */ = { isa = PBXGroup; children = ( - 277794041DF221F800573F3E /* ClaimSet.swift */, - 2777940A1DF22BE400573F3E /* JOSEHeader.swift */, - 520A71131C469F010005C709 /* Base64.swift */, - 520A71141C469F010005C709 /* Claims.swift */, - 520A71151C469F010005C709 /* Decode.swift */, - 2777940F1DF22D0D00573F3E /* Encode.swift */, - 520A71161C469F010005C709 /* JWT.swift */, - 271E107F1F90253300B5033C /* JWA.swift */, - 273010FE1F33EABA00219C35 /* HMAC.swift */, - 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */, - 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */, + 271E10861F902D8900B5033C /* JWT */, ); path = Sources; sourceTree = ""; diff --git a/Package.swift b/Package.swift index eb6f28b..707de2f 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,7 @@ let package = Package( .Package(url: "https://github.com/kylef-archive/CommonCrypto.git", majorVersion: 1), ], exclude: [ - "Sources/HMACCryptoSwift.swift", + "Sources/JWT/HMACCryptoSwift.swift", ] ) #else @@ -18,7 +18,7 @@ let package = Package( .Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0, minor: 6), ], exclude: [ - "Sources/HMACCommonCrypto.swift", + "Sources/JWT/HMACCommonCrypto.swift", ] ) #endif diff --git a/Sources/Base64.swift b/Sources/JWT/Base64.swift similarity index 100% rename from Sources/Base64.swift rename to Sources/JWT/Base64.swift diff --git a/Sources/ClaimSet.swift b/Sources/JWT/ClaimSet.swift similarity index 100% rename from Sources/ClaimSet.swift rename to Sources/JWT/ClaimSet.swift diff --git a/Sources/Claims.swift b/Sources/JWT/Claims.swift similarity index 100% rename from Sources/Claims.swift rename to Sources/JWT/Claims.swift diff --git a/Sources/Decode.swift b/Sources/JWT/Decode.swift similarity index 100% rename from Sources/Decode.swift rename to Sources/JWT/Decode.swift diff --git a/Sources/Encode.swift b/Sources/JWT/Encode.swift similarity index 100% rename from Sources/Encode.swift rename to Sources/JWT/Encode.swift diff --git a/Sources/HMAC.swift b/Sources/JWT/HMAC.swift similarity index 100% rename from Sources/HMAC.swift rename to Sources/JWT/HMAC.swift diff --git a/Sources/HMACCommonCrypto.swift b/Sources/JWT/HMACCommonCrypto.swift similarity index 100% rename from Sources/HMACCommonCrypto.swift rename to Sources/JWT/HMACCommonCrypto.swift diff --git a/Sources/HMACCryptoSwift.swift b/Sources/JWT/HMACCryptoSwift.swift similarity index 100% rename from Sources/HMACCryptoSwift.swift rename to Sources/JWT/HMACCryptoSwift.swift diff --git a/Sources/JOSEHeader.swift b/Sources/JWT/JOSEHeader.swift similarity index 100% rename from Sources/JOSEHeader.swift rename to Sources/JWT/JOSEHeader.swift diff --git a/Sources/JWA.swift b/Sources/JWT/JWA.swift similarity index 98% rename from Sources/JWA.swift rename to Sources/JWT/JWA.swift index 950b1b1..3ac9cef 100644 --- a/Sources/JWA.swift +++ b/Sources/JWT/JWA.swift @@ -1,3 +1,5 @@ +import Foundation + /// Represents a JSON Web Algorithm (JWA) /// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 public enum Algorithm: CustomStringConvertible { diff --git a/Sources/JWT.swift b/Sources/JWT/JWT.swift similarity index 100% rename from Sources/JWT.swift rename to Sources/JWT/JWT.swift From 69866e1cb1f72d6a61ebaa45615f4bc6c4350ee7 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 01:59:31 +0200 Subject: [PATCH 087/127] refactor: Implement Compact JSON Coders --- JWT.xcodeproj/project.pbxproj | 8 ++++++++ Sources/JWT/Base64.swift | 2 +- Sources/JWT/CompactJSONDecoder.swift | 9 +++++++++ Sources/JWT/CompactJSONEncoder.swift | 9 +++++++++ Sources/JWT/Encode.swift | 4 +++- 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 Sources/JWT/CompactJSONDecoder.swift create mode 100644 Sources/JWT/CompactJSONEncoder.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 3562610..f1e8625 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 271E10821F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 271E10831F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 271E10851F90274A00B5033C /* JOSEHeaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */; }; + 271E10891F90334B00B5033C /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; + 271E108B1F9034B100B5033C /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; @@ -69,6 +71,8 @@ /* Begin PBXFileReference section */ 271E107F1F90253300B5033C /* JWA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWA.swift; sourceTree = ""; }; 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JOSEHeaderTests.swift; sourceTree = ""; }; + 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONEncoder.swift; sourceTree = ""; }; + 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoder.swift; sourceTree = ""; }; 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; @@ -138,6 +142,8 @@ children = ( 277794041DF221F800573F3E /* ClaimSet.swift */, 2777940A1DF22BE400573F3E /* JOSEHeader.swift */, + 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */, + 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */, 520A71131C469F010005C709 /* Base64.swift */, 520A71141C469F010005C709 /* Claims.swift */, 520A71151C469F010005C709 /* Decode.swift */, @@ -445,12 +451,14 @@ 271E10801F90253300B5033C /* JWA.swift in Sources */, 273011161F34029900219C35 /* HMACCommonCrypto.swift in Sources */, 520A71181C469F010005C709 /* Claims.swift in Sources */, + 271E10891F90334B00B5033C /* CompactJSONEncoder.swift in Sources */, 520A711A1C469F010005C709 /* JWT.swift in Sources */, 520A71191C469F010005C709 /* Decode.swift in Sources */, 277794101DF22D0D00573F3E /* Encode.swift in Sources */, 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */, + 271E108B1F9034B100B5033C /* CompactJSONDecoder.swift in Sources */, 520A71171C469F010005C709 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/JWT/Base64.swift b/Sources/JWT/Base64.swift index c85719b..f6bb78e 100644 --- a/Sources/JWT/Base64.swift +++ b/Sources/JWT/Base64.swift @@ -12,7 +12,7 @@ func base64encode(_ input: Data) -> String { /// URI Safe base64 decode func base64decode(_ input: String) -> Data? { - let rem = input.characters.count % 4 + let rem = input.count % 4 var ending = "" if rem > 0 { diff --git a/Sources/JWT/CompactJSONDecoder.swift b/Sources/JWT/CompactJSONDecoder.swift new file mode 100644 index 0000000..1d29309 --- /dev/null +++ b/Sources/JWT/CompactJSONDecoder.swift @@ -0,0 +1,9 @@ +class CompactJSONDecoder: JSONDecoder { + override func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { + guard let string = String(data: data, encoding: .ascii) else { + fatalError() + } + + return try super.decode(type, from: base64decode(string)!) + } +} diff --git a/Sources/JWT/CompactJSONEncoder.swift b/Sources/JWT/CompactJSONEncoder.swift new file mode 100644 index 0000000..c3e454f --- /dev/null +++ b/Sources/JWT/CompactJSONEncoder.swift @@ -0,0 +1,9 @@ +class CompactJSONEncoder: JSONEncoder { + override func encode(_ value: T) throws -> Data { + return try encodeString(value).data(using: .ascii) ?? Data() + } + + func encodeString(_ value: T) throws -> String { + return base64encode(try super.encode(value)) + } +} diff --git a/Sources/JWT/Encode.swift b/Sources/JWT/Encode.swift index fa716d1..3c5bb68 100644 --- a/Sources/JWT/Encode.swift +++ b/Sources/JWT/Encode.swift @@ -6,6 +6,8 @@ import Foundation - returns: The JSON web token as a String */ public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: String]? = nil) -> String { + let encoder = CompactJSONEncoder() + func encodeJSON(_ payload: [String: Any]) -> String? { if let data = try? JSONSerialization.data(withJSONObject: payload) { return base64encode(data) @@ -20,7 +22,7 @@ public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: Str } headers["alg"] = algorithm.description - let header = encodeJSON(headers)! + let header = try! encoder.encodeString(headers) let payload = encodeJSON(claims.claims)! let signingInput = "\(header).\(payload)" let signature = algorithm.sign(signingInput) From a678be236990dee411b0f80b6737d58c4d84cd6d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 02:47:07 +0200 Subject: [PATCH 088/127] refactor: Make JOSEHeader Codable --- JWT.xcodeproj/project.pbxproj | 12 ++++-- Sources/JWT/CompactJSONDecoder.swift | 12 +++++- Sources/JWT/Decode.swift | 12 ++---- Sources/JWT/JOSEHeader.swift | 36 +++++++---------- Tests/JWTTests/CompactJSONDecoderTests.swift | 16 ++++++++ Tests/JWTTests/CompactJSONEncoderTests.swift | 23 +++++++++++ Tests/JWTTests/JOSEHeaderTests.swift | 42 -------------------- 7 files changed, 75 insertions(+), 78 deletions(-) create mode 100644 Tests/JWTTests/CompactJSONDecoderTests.swift create mode 100644 Tests/JWTTests/CompactJSONEncoderTests.swift delete mode 100644 Tests/JWTTests/JOSEHeaderTests.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index f1e8625..3a210ac 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -11,9 +11,10 @@ 271E10811F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 271E10821F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; 271E10831F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; - 271E10851F90274A00B5033C /* JOSEHeaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */; }; 271E10891F90334B00B5033C /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; 271E108B1F9034B100B5033C /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; + 271E108D1F9041C400B5033C /* CompactJSONDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */; }; + 271E108F1F9042E900B5033C /* CompactJSONEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */; }; 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; @@ -70,9 +71,10 @@ /* Begin PBXFileReference section */ 271E107F1F90253300B5033C /* JWA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWA.swift; sourceTree = ""; }; - 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JOSEHeaderTests.swift; sourceTree = ""; }; 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONEncoder.swift; sourceTree = ""; }; 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoder.swift; sourceTree = ""; }; + 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoderTests.swift; sourceTree = ""; }; + 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONEncoderTests.swift; sourceTree = ""; }; 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; @@ -204,8 +206,9 @@ 279D63AB1AD07FFF0024E2BC /* Tests */ = { isa = PBXGroup; children = ( + 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */, + 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */, 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */, - 271E10841F90274A00B5033C /* JOSEHeaderTests.swift */, 279D63AC1AD07FFF0024E2BC /* Supporting Files */, ); name = Tests; @@ -467,8 +470,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 271E108F1F9042E900B5033C /* CompactJSONEncoderTests.swift in Sources */, + 271E108D1F9041C400B5033C /* CompactJSONDecoderTests.swift in Sources */, 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */, - 271E10851F90274A00B5033C /* JOSEHeaderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/JWT/CompactJSONDecoder.swift b/Sources/JWT/CompactJSONDecoder.swift index 1d29309..0606395 100644 --- a/Sources/JWT/CompactJSONDecoder.swift +++ b/Sources/JWT/CompactJSONDecoder.swift @@ -1,9 +1,17 @@ class CompactJSONDecoder: JSONDecoder { override func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { guard let string = String(data: data, encoding: .ascii) else { - fatalError() + throw InvalidToken.decodeError("data should contain only ASCII characters") } - return try super.decode(type, from: base64decode(string)!) + return try decode(type, from: string) + } + + func decode(_ type: T.Type, from string: String) throws -> T where T : Decodable { + guard let decoded = base64decode(string) else { + throw InvalidToken.decodeError("data should be a valid base64 string") + } + + return try super.decode(type, from: decoded) } } diff --git a/Sources/JWT/Decode.swift b/Sources/JWT/Decode.swift index 3054160..c04bad6 100644 --- a/Sources/JWT/Decode.swift +++ b/Sources/JWT/Decode.swift @@ -88,14 +88,8 @@ func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signa let signatureSegment = segments[2] let signatureInput = "\(headerSegment).\(payloadSegment)" - guard let headerData = base64decode(headerSegment) else { - throw InvalidToken.decodeError("Header is not correctly encoded as base64") - } - - let header = (try? JSONSerialization.jsonObject(with: headerData, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload - if header == nil { - throw InvalidToken.decodeError("Invalid header") - } + let decoder = CompactJSONDecoder() + let header = try decoder.decode(JOSEHeader.self, from: headerSegment) let payloadData = base64decode(payloadSegment) if payloadData == nil { @@ -111,7 +105,7 @@ func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signa throw InvalidToken.decodeError("Signature is not correctly encoded as base64") } - return (header: JOSEHeader(parameters: header!), payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput) + return (header: header, payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput) } // MARK: Signature Verification diff --git a/Sources/JWT/JOSEHeader.swift b/Sources/JWT/JOSEHeader.swift index 4bfcf49..de48742 100644 --- a/Sources/JWT/JOSEHeader.swift +++ b/Sources/JWT/JOSEHeader.swift @@ -9,30 +9,24 @@ import Foundation -struct JOSEHeader { - var parameters: [String: Any] - - init(parameters: [String: Any]) { - self.parameters = parameters +struct JOSEHeader: Codable { + var type: String? + var algorithm: String? + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + type = try container.decodeIfPresent(String.self, forKey: .type) + algorithm = try container.decodeIfPresent(String.self, forKey: .algorithm) } - var algorithm: String? { - get { - return parameters["alg"] as? String - } - - set { - parameters["alg"] = newValue - } + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(type, forKey: .type) + try container.encodeIfPresent(algorithm, forKey: .algorithm) } - var type: String? { - get { - return parameters["typ"] as? String - } - - set { - parameters["typ"] = newValue - } + enum CodingKeys: String, CodingKey { + case type = "typ" + case algorithm = "alg" } } diff --git a/Tests/JWTTests/CompactJSONDecoderTests.swift b/Tests/JWTTests/CompactJSONDecoderTests.swift new file mode 100644 index 0000000..ed1bf26 --- /dev/null +++ b/Tests/JWTTests/CompactJSONDecoderTests.swift @@ -0,0 +1,16 @@ +import XCTest +@testable import JWT + +class CompactJSONDecodable: Decodable { + let key: String +} + +class CompactJSONDecoderTests: XCTestCase { + let decoder = CompactJSONDecoder() + + func testDecoder() throws { + let expected = "eyJrZXkiOiJ2YWx1ZSJ9".data(using: .ascii)! + let value = try decoder.decode(CompactJSONDecodable.self, from: expected) + XCTAssertEqual(value.key, "value") + } +} diff --git a/Tests/JWTTests/CompactJSONEncoderTests.swift b/Tests/JWTTests/CompactJSONEncoderTests.swift new file mode 100644 index 0000000..a0f59cd --- /dev/null +++ b/Tests/JWTTests/CompactJSONEncoderTests.swift @@ -0,0 +1,23 @@ +import XCTest +@testable import JWT + +class CompactJSONEncodable: Encodable { + let key: String + + init(key: String) { + self.key = key + } +} + +class CompactJSONEncoderTests: XCTestCase { + let encoder = CompactJSONEncoder() + + func testEncode() throws { + let value = CompactJSONEncodable(key: "value") + + let encoded = try encoder.encode(value) + + XCTAssertEqual(encoded, "eyJrZXkiOiJ2YWx1ZSJ9".data(using: .ascii)!) + } +} + diff --git a/Tests/JWTTests/JOSEHeaderTests.swift b/Tests/JWTTests/JOSEHeaderTests.swift deleted file mode 100644 index 44af163..0000000 --- a/Tests/JWTTests/JOSEHeaderTests.swift +++ /dev/null @@ -1,42 +0,0 @@ -import XCTest -@testable import JWT - -class JOSEHeaderTests: XCTestCase { - // MARK: Algorithm - - func testGettingUnsetAlgoritm() { - let header = JOSEHeader(parameters: [:]) - XCTAssertNil(header.algorithm) - } - - func testGettingAlgoritm() { - let header = JOSEHeader(parameters: ["alg": "none"]) - XCTAssertEqual(header.algorithm, "none") - } - - func testSettingAlgoritm() { - var header = JOSEHeader(parameters: [:]) - - header.algorithm = "none" - XCTAssertEqual(header.algorithm, "none") - } - - // MARK: Type - - func testGettingUnsetType() { - let header = JOSEHeader(parameters: [:]) - XCTAssertNil(header.type) - } - - func testGettingType() { - let header = JOSEHeader(parameters: ["typ": "JWT"]) - XCTAssertEqual(header.type, "JWT") - } - - func testSettingType() { - var header = JOSEHeader(parameters: [:]) - - header.type = "JWT" - XCTAssertEqual(header.type, "JWT") - } -} From 28fc53d58b574828efe64c5653c8e120e633caa2 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 03:00:21 +0200 Subject: [PATCH 089/127] refactor: Add keyID and contentType to JOSEHeader --- Sources/JWT/JOSEHeader.swift | 44 ++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/Sources/JWT/JOSEHeader.swift b/Sources/JWT/JOSEHeader.swift index de48742..3e673e7 100644 --- a/Sources/JWT/JOSEHeader.swift +++ b/Sources/JWT/JOSEHeader.swift @@ -10,23 +10,59 @@ import Foundation struct JOSEHeader: Codable { - var type: String? + /// The "alg" (algorithm) identifies the cryptographic algorithm used to secure the JWS var algorithm: String? + /// jwu + // TODO + + /// jwk + // TODO + + /// The "kid" (key ID) is a hint indicating which key was used to secure the JWS + var keyID: String? + + /// x5u + // TODO + + /// x5c + // TODO + + /// x5t + // TODO + + /// x5t#S256 + // TODO + + /// The "typ" (type) is used by JWS applications to declare the media type [IANA.MediaTypes] of this complete JWS + var type: String? + + /// The "cty" (content type) is used by JWS application to declare the media type [IANA.MediaTypes] of the secured content (the payload). + var contentType: String? + + /// The "crit" (critical) indicates that extensions to JWS, JWE and/or [JWA] are being used that MUST be understood and processed + // TODO + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - type = try container.decodeIfPresent(String.self, forKey: .type) algorithm = try container.decodeIfPresent(String.self, forKey: .algorithm) + keyID = try container.decodeIfPresent(String.self, forKey: .keyID) + type = try container.decodeIfPresent(String.self, forKey: .type) + contentType = try container.decodeIfPresent(String.self, forKey: .contentType) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encodeIfPresent(type, forKey: .type) try container.encodeIfPresent(algorithm, forKey: .algorithm) + try container.encodeIfPresent(keyID, forKey: .keyID) + try container.encodeIfPresent(type, forKey: .type) + try container.encodeIfPresent(contentType, forKey: .contentType) } enum CodingKeys: String, CodingKey { - case type = "typ" case algorithm = "alg" + case keyID = "kid" + case type = "typ" + case contentType = "cty" } } From 1a829a4ea3ab4cb17ce1aefe39552b9a6c03be50 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 03:03:31 +0200 Subject: [PATCH 090/127] refactor: Don't provide blank options --- Sources/JWT/Base64.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/JWT/Base64.swift b/Sources/JWT/Base64.swift index f6bb78e..4a93f7f 100644 --- a/Sources/JWT/Base64.swift +++ b/Sources/JWT/Base64.swift @@ -2,12 +2,12 @@ import Foundation /// URI Safe base64 encode func base64encode(_ input: Data) -> String { - let data = input.base64EncodedData(options: NSData.Base64EncodingOptions(rawValue: 0)) + let data = input.base64EncodedData() let string = String(data: data, encoding: .utf8)! return string - .replacingOccurrences(of: "+", with: "-", options: NSString.CompareOptions(rawValue: 0), range: nil) - .replacingOccurrences(of: "/", with: "_", options: NSString.CompareOptions(rawValue: 0), range: nil) - .replacingOccurrences(of: "=", with: "", options: NSString.CompareOptions(rawValue: 0), range: nil) + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "=", with: "") } /// URI Safe base64 decode @@ -20,8 +20,8 @@ func base64decode(_ input: String) -> Data? { ending = String(repeating: "=", count: amount) } - let base64 = input.replacingOccurrences(of: "-", with: "+", options: NSString.CompareOptions(rawValue: 0), range: nil) - .replacingOccurrences(of: "_", with: "/", options: NSString.CompareOptions(rawValue: 0), range: nil) + ending + let base64 = input.replacingOccurrences(of: "-", with: "+") + .replacingOccurrences(of: "_", with: "/") + ending - return Data(base64Encoded: base64, options: NSData.Base64DecodingOptions(rawValue: 0)) + return Data(base64Encoded: base64) } From 71875415e2a8f3104acf33afc0873bf5d366bda0 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 03:11:33 +0200 Subject: [PATCH 091/127] refactor: Split tests into separate files --- JWT.xcodeproj/project.pbxproj | 24 ++- Tests/JWTTests/ClaimSetTests.swift | 79 +++++++ Tests/JWTTests/IntegrationTests.swift | 40 ++++ .../{JWTTests.swift => JWTDecodeTests.swift} | 202 ------------------ Tests/JWTTests/JWTEncodeTests.swift | 36 ++++ Tests/JWTTests/PayloadTests.swift | 54 +++++ 6 files changed, 229 insertions(+), 206 deletions(-) create mode 100644 Tests/JWTTests/ClaimSetTests.swift create mode 100644 Tests/JWTTests/IntegrationTests.swift rename Tests/JWTTests/{JWTTests.swift => JWTDecodeTests.swift} (60%) create mode 100644 Tests/JWTTests/JWTEncodeTests.swift create mode 100644 Tests/JWTTests/PayloadTests.swift diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 3a210ac..3d926c3 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -15,6 +15,10 @@ 271E108B1F9034B100B5033C /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; 271E108D1F9041C400B5033C /* CompactJSONDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */; }; 271E108F1F9042E900B5033C /* CompactJSONEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */; }; + 271E10911F90488700B5033C /* JWTEncodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10901F90488700B5033C /* JWTEncodeTests.swift */; }; + 271E10931F9049A400B5033C /* PayloadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10921F9049A400B5033C /* PayloadTests.swift */; }; + 271E10951F9049E200B5033C /* ClaimSetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10941F9049E200B5033C /* ClaimSetTests.swift */; }; + 271E10971F904A0700B5033C /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10961F904A0700B5033C /* IntegrationTests.swift */; }; 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; @@ -37,7 +41,7 @@ 277794131DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; - 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; }; + 279D63AF1AD07FFF0024E2BC /* JWTDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */; }; 520A71171C469F010005C709 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; 520A71181C469F010005C709 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; @@ -75,6 +79,10 @@ 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoder.swift; sourceTree = ""; }; 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoderTests.swift; sourceTree = ""; }; 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONEncoderTests.swift; sourceTree = ""; }; + 271E10901F90488700B5033C /* JWTEncodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTEncodeTests.swift; sourceTree = ""; }; + 271E10921F9049A400B5033C /* PayloadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadTests.swift; sourceTree = ""; }; + 271E10941F9049E200B5033C /* ClaimSetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClaimSetTests.swift; sourceTree = ""; }; + 271E10961F904A0700B5033C /* IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = ""; }; 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; @@ -86,7 +94,7 @@ 279D63A11AD07FFF0024E2BC /* JWT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JWT.h; sourceTree = ""; }; 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JWTTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 279D63AD1AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTTests.swift; sourceTree = ""; }; + 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTDecodeTests.swift; sourceTree = ""; }; 520A71131C469F010005C709 /* Base64.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base64.swift; sourceTree = ""; }; 520A71141C469F010005C709 /* Claims.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Claims.swift; sourceTree = ""; }; 520A71151C469F010005C709 /* Decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decode.swift; sourceTree = ""; }; @@ -208,7 +216,11 @@ children = ( 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */, 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */, - 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */, + 271E10941F9049E200B5033C /* ClaimSetTests.swift */, + 271E10921F9049A400B5033C /* PayloadTests.swift */, + 271E10901F90488700B5033C /* JWTEncodeTests.swift */, + 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */, + 271E10961F904A0700B5033C /* IntegrationTests.swift */, 279D63AC1AD07FFF0024E2BC /* Supporting Files */, ); name = Tests; @@ -470,9 +482,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 271E10971F904A0700B5033C /* IntegrationTests.swift in Sources */, 271E108F1F9042E900B5033C /* CompactJSONEncoderTests.swift in Sources */, + 271E10911F90488700B5033C /* JWTEncodeTests.swift in Sources */, 271E108D1F9041C400B5033C /* CompactJSONDecoderTests.swift in Sources */, - 279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */, + 279D63AF1AD07FFF0024E2BC /* JWTDecodeTests.swift in Sources */, + 271E10931F9049A400B5033C /* PayloadTests.swift in Sources */, + 271E10951F9049E200B5033C /* ClaimSetTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/JWTTests/ClaimSetTests.swift b/Tests/JWTTests/ClaimSetTests.swift new file mode 100644 index 0000000..594e648 --- /dev/null +++ b/Tests/JWTTests/ClaimSetTests.swift @@ -0,0 +1,79 @@ +import XCTest +import JWT + +class ValidationTests: XCTestCase { + func testClaimJustExpiredWithoutLeeway() { + var claims = ClaimSet() + claims.expiration = Date().addingTimeInterval(-1) + + do { + try claims.validateExpiary() + XCTFail("InvalidToken.expiredSignature error should have been thrown.") + } catch InvalidToken.expiredSignature { + // Correct error thrown + } catch { + XCTFail("Unexpected error while validating exp claim.") + } + } + + func testClaimJustNotExpiredWithoutLeeway() { + var claims = ClaimSet() + claims.expiration = Date().addingTimeInterval(-1) + + do { + try claims.validateExpiary(leeway: 2) + } catch { + XCTFail("Unexpected error while validating exp claim that should be valid with leeway.") + } + } + + func testNotBeforeIsImmatureSignatureWithoutLeeway() { + var claims = ClaimSet() + claims.notBefore = Date().addingTimeInterval(1) + + do { + try claims.validateNotBefore() + XCTFail("InvalidToken.immatureSignature error should have been thrown.") + } catch InvalidToken.immatureSignature { + // Correct error thrown + } catch { + XCTFail("Unexpected error while validating nbf claim.") + } + } + + func testNotBeforeIsValidWithLeeway() { + var claims = ClaimSet() + claims.notBefore = Date().addingTimeInterval(1) + + do { + try claims.validateNotBefore(leeway: 2) + } catch { + XCTFail("Unexpected error while validating nbf claim that should be valid with leeway.") + } + } + + func testIssuedAtIsInFutureWithoutLeeway() { + var claims = ClaimSet() + claims.issuedAt = Date().addingTimeInterval(1) + + do { + try claims.validateIssuedAt() + XCTFail("InvalidToken.invalidIssuedAt error should have been thrown.") + } catch InvalidToken.invalidIssuedAt { + // Correct error thrown + } catch { + XCTFail("Unexpected error while validating iat claim.") + } + } + + func testIssuedAtIsValidWithLeeway() { + var claims = ClaimSet() + claims.issuedAt = Date().addingTimeInterval(1) + + do { + try claims.validateIssuedAt(leeway: 2) + } catch { + XCTFail("Unexpected error while validating iat claim that should be valid with leeway.") + } + } +} diff --git a/Tests/JWTTests/IntegrationTests.swift b/Tests/JWTTests/IntegrationTests.swift new file mode 100644 index 0000000..f15b9d9 --- /dev/null +++ b/Tests/JWTTests/IntegrationTests.swift @@ -0,0 +1,40 @@ +import XCTest +import JWT + +class IntegrationTests: XCTestCase { + func testVerificationFailureWithoutLeeway() { + let token = JWT.encode(.none) { builder in + builder.issuer = "fuller.li" + builder.audience = "cocoapods" + builder.expiration = Date().addingTimeInterval(-1) // Token expired one second ago + builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second + builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future + } + + do { + let _ = try JWT.decode(token, algorithm: .none, leeway: 0) + XCTFail("InvalidToken error should have been thrown.") + } catch is InvalidToken { + // Correct error thrown + } catch { + XCTFail("Unexpected error type while verifying token.") + } + } + + func testVerificationSuccessWithLeeway() { + let token = JWT.encode(.none) { builder in + builder.issuer = "fuller.li" + builder.audience = "cocoapods" + builder.expiration = Date().addingTimeInterval(-1) // Token expired one second ago + builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second + builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future + } + + do { + let _ = try JWT.decode(token, algorithm: .none, leeway: 2) + // Due to leeway no error gets thrown. + } catch { + XCTFail("Unexpected error type while verifying token.") + } + } +} diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTDecodeTests.swift similarity index 60% rename from Tests/JWTTests/JWTTests.swift rename to Tests/JWTTests/JWTDecodeTests.swift index b8ffe50..8286e6e 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -2,93 +2,6 @@ import Foundation import XCTest import JWT -class EncodeTests: XCTestCase { - func testEncodingJWT() { - let payload = ["name": "Kyle"] as Payload - let jwt = JWT.encode(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", - ] - - 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" - } - - assertSuccess(try JWT.decode(jwt, algorithm: algorithm)) { payload in - XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"]) - } - } - - 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") - } -} - -class PayloadTests: XCTestCase { - func testIssuer() { - _ = JWT.encode(.none) { builder in - builder.issuer = "fuller.li" - XCTAssertEqual(builder.issuer, "fuller.li") - XCTAssertEqual(builder["iss"] as? String, "fuller.li") - } - } - - func testAudience() { - _ = JWT.encode(.none) { builder in - builder.audience = "cocoapods" - XCTAssertEqual(builder.audience, "cocoapods") - XCTAssertEqual(builder["aud"] as? String, "cocoapods") - } - } - - func testExpiration() { - _ = JWT.encode(.none) { builder in - let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) - builder.expiration = date - XCTAssertEqual(builder.expiration, date) - XCTAssertEqual(builder["exp"] as? TimeInterval, date.timeIntervalSince1970) - } - } - - func testNotBefore() { - _ = JWT.encode(.none) { builder in - let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) - builder.notBefore = date - XCTAssertEqual(builder.notBefore, date) - XCTAssertEqual(builder["nbf"] as? TimeInterval, date.timeIntervalSince1970) - } - } - - func testIssuedAt() { - _ = JWT.encode(.none) { builder in - let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) - builder.issuedAt = date - XCTAssertEqual(builder.issuedAt, date) - XCTAssertEqual(builder["iat"] as? TimeInterval, date.timeIntervalSince1970) - } - } - - func testCustomAttributes() { - _ = JWT.encode(.none) { builder in - builder["user"] = "kyle" - XCTAssertEqual(builder["user"] as? String, "kyle") - } - } -} - class DecodeTests: XCTestCase { func testDecodingValidJWTAsClaimSet() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" @@ -279,121 +192,6 @@ class DecodeTests: XCTestCase { } } -class ValidationTests: XCTestCase { - func testClaimJustExpiredWithoutLeeway() { - var claims = ClaimSet() - claims.expiration = Date().addingTimeInterval(-1) - - do { - try claims.validateExpiary() - XCTFail("InvalidToken.expiredSignature error should have been thrown.") - } catch InvalidToken.expiredSignature { - // Correct error thrown - } catch { - XCTFail("Unexpected error while validating exp claim.") - } - } - - func testClaimJustNotExpiredWithoutLeeway() { - var claims = ClaimSet() - claims.expiration = Date().addingTimeInterval(-1) - - do { - try claims.validateExpiary(leeway: 2) - } catch { - XCTFail("Unexpected error while validating exp claim that should be valid with leeway.") - } - } - - func testNotBeforeIsImmatureSignatureWithoutLeeway() { - var claims = ClaimSet() - claims.notBefore = Date().addingTimeInterval(1) - - do { - try claims.validateNotBefore() - XCTFail("InvalidToken.immatureSignature error should have been thrown.") - } catch InvalidToken.immatureSignature { - // Correct error thrown - } catch { - XCTFail("Unexpected error while validating nbf claim.") - } - } - - func testNotBeforeIsValidWithLeeway() { - var claims = ClaimSet() - claims.notBefore = Date().addingTimeInterval(1) - - do { - try claims.validateNotBefore(leeway: 2) - } catch { - XCTFail("Unexpected error while validating nbf claim that should be valid with leeway.") - } - } - - func testIssuedAtIsInFutureWithoutLeeway() { - var claims = ClaimSet() - claims.issuedAt = Date().addingTimeInterval(1) - - do { - try claims.validateIssuedAt() - XCTFail("InvalidToken.invalidIssuedAt error should have been thrown.") - } catch InvalidToken.invalidIssuedAt { - // Correct error thrown - } catch { - XCTFail("Unexpected error while validating iat claim.") - } - } - - func testIssuedAtIsValidWithLeeway() { - var claims = ClaimSet() - claims.issuedAt = Date().addingTimeInterval(1) - - do { - try claims.validateIssuedAt(leeway: 2) - } catch { - XCTFail("Unexpected error while validating iat claim that should be valid with leeway.") - } - } -} - -class IntegrationTests: XCTestCase { - func testVerificationFailureWithoutLeeway() { - let token = JWT.encode(.none) { builder in - builder.issuer = "fuller.li" - builder.audience = "cocoapods" - builder.expiration = Date().addingTimeInterval(-1) // Token expired one second ago - builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second - builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future - } - - do { - let _ = try JWT.decode(token, algorithm: .none, leeway: 0) - XCTFail("InvalidToken error should have been thrown.") - } catch is InvalidToken { - // Correct error thrown - } catch { - XCTFail("Unexpected error type while verifying token.") - } - } - - func testVerificationSuccessWithLeeway() { - let token = JWT.encode(.none) { builder in - builder.issuer = "fuller.li" - builder.audience = "cocoapods" - builder.expiration = Date().addingTimeInterval(-1) // Token expired one second ago - builder.notBefore = Date().addingTimeInterval(1) // Token starts being valid in one second - builder.issuedAt = Date().addingTimeInterval(1) // Token is issued one second in the future - } - - do { - let _ = try JWT.decode(token, algorithm: .none, leeway: 2) - // Due to leeway no error gets thrown. - } catch { - XCTFail("Unexpected error type while verifying token.") - } - } -} - // MARK: Helpers func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure: ((Payload) -> Void)? = nil) { diff --git a/Tests/JWTTests/JWTEncodeTests.swift b/Tests/JWTTests/JWTEncodeTests.swift new file mode 100644 index 0000000..0dbb7b3 --- /dev/null +++ b/Tests/JWTTests/JWTEncodeTests.swift @@ -0,0 +1,36 @@ +import XCTest +import JWT + + +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", + ] + + 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") + } + + 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") + } +} diff --git a/Tests/JWTTests/PayloadTests.swift b/Tests/JWTTests/PayloadTests.swift new file mode 100644 index 0000000..150be11 --- /dev/null +++ b/Tests/JWTTests/PayloadTests.swift @@ -0,0 +1,54 @@ +import XCTest +import JWT + +class PayloadTests: XCTestCase { + func testIssuer() { + _ = JWT.encode(.none) { builder in + builder.issuer = "fuller.li" + XCTAssertEqual(builder.issuer, "fuller.li") + XCTAssertEqual(builder["iss"] as? String, "fuller.li") + } + } + + func testAudience() { + _ = JWT.encode(.none) { builder in + builder.audience = "cocoapods" + XCTAssertEqual(builder.audience, "cocoapods") + XCTAssertEqual(builder["aud"] as? String, "cocoapods") + } + } + + func testExpiration() { + _ = JWT.encode(.none) { builder in + let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) + builder.expiration = date + XCTAssertEqual(builder.expiration, date) + XCTAssertEqual(builder["exp"] as? TimeInterval, date.timeIntervalSince1970) + } + } + + func testNotBefore() { + _ = JWT.encode(.none) { builder in + let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) + builder.notBefore = date + XCTAssertEqual(builder.notBefore, date) + XCTAssertEqual(builder["nbf"] as? TimeInterval, date.timeIntervalSince1970) + } + } + + func testIssuedAt() { + _ = JWT.encode(.none) { builder in + let date = Date(timeIntervalSince1970: Date().timeIntervalSince1970) + builder.issuedAt = date + XCTAssertEqual(builder.issuedAt, date) + XCTAssertEqual(builder["iat"] as? TimeInterval, date.timeIntervalSince1970) + } + } + + func testCustomAttributes() { + _ = JWT.encode(.none) { builder in + builder["user"] = "kyle" + XCTAssertEqual(builder["user"] as? String, "kyle") + } + } +} From 7154710df7220d63ccd9ab049f32a569d6c32a37 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 03:27:31 +0200 Subject: [PATCH 092/127] refactor: Use XCT for validating raising --- Sources/JWT/ClaimSet.swift | 32 ++++++----- Tests/JWTTests/JWTDecodeTests.swift | 87 ++++++++++++++--------------- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/Sources/JWT/ClaimSet.swift b/Sources/JWT/ClaimSet.swift index 7dcf872..114c04e 100644 --- a/Sources/JWT/ClaimSet.swift +++ b/Sources/JWT/ClaimSet.swift @@ -1,5 +1,19 @@ import Foundation +func parseTimeInterval(_ value: Any?) -> Date? { + guard let value = value else { return nil } + + if let string = value as? String, let interval = TimeInterval(string) { + return Date(timeIntervalSince1970: interval) + } + + if let interval = value as? TimeInterval { + return Date(timeIntervalSince1970: interval) + } + + return nil +} + public struct ClaimSet { var claims: [String: Any] @@ -48,11 +62,7 @@ extension ClaimSet { public var expiration: Date? { get { - if let expiration = claims["exp"] as? TimeInterval { - return Date(timeIntervalSince1970: expiration) - } - - return nil + return parseTimeInterval(claims["exp"]) } set { @@ -62,11 +72,7 @@ extension ClaimSet { public var notBefore: Date? { get { - if let notBefore = claims["nbf"] as? TimeInterval { - return Date(timeIntervalSince1970: notBefore) - } - - return nil + return parseTimeInterval(claims["nbf"]) } set { @@ -76,11 +82,7 @@ extension ClaimSet { public var issuedAt: Date? { get { - if let issuedAt = claims["iat"] as? TimeInterval { - return Date(timeIntervalSince1970: issuedAt) - } - - return nil + return parseTimeInterval(claims["iat"]) } set { diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index 8286e6e..24a17b3 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -10,86 +10,85 @@ class DecodeTests: XCTestCase { XCTAssertEqual(claims["name"] as? String, "Kyle") } - func testDecodingValidJWT() { + func testDecodingValidJWT() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg" - assertSuccess(try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: String], ["name": "Kyle"]) - } + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims["name"] as? String, "Kyle") } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - assertDecodeError(try decode("a.b", algorithm: .none), error: "Not enough segments") + XCTAssertThrowsError(try decode("a.b", algorithm: .none), "Not enough segments") } // MARK: Disable verify - func testDisablingVerify() { + func testDisablingVerify() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertSuccess(try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li")) + _ = try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li") as ClaimSet } // MARK: Issuer claim - func testSuccessfulIssuerValidation() { + func testSuccessfulIssuerValidation() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) { payload in - XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.issuer, "fuller.li") } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } - func testUnexpiredClaim() { + func testUnexpiredClaim() throws { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: Int], ["exp": 1728188491]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) } - func testUnexpiredClaimString() { + func testUnexpiredClaimString() throws { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: String], ["exp": "1728188491"]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) } // MARK: Not before claim - func testNotBeforeClaim() { + func testNotBeforeClaim() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: Int], ["nbf": 1428189720]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720) } - func testNotBeforeClaimString() { + func testNotBeforeClaimString() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: String], ["nbf": "1428189720"]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720) } func testInvalidNotBeforeClaim() { @@ -100,29 +99,29 @@ class DecodeTests: XCTestCase { func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } // MARK: Issued at claim - func testIssuedAtClaimInThePast() { + func testIssuedAtClaimInThePast() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: Int], ["iat": 1428189720]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720) } - func testIssuedAtClaimInThePastString() { + func testIssuedAtClaimInThePastString() throws { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in - XCTAssertEqual(payload as! [String: String], ["iat": "1428189720"]) - } + + let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) + XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720) } func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testInvalidIssuedAtClaim() { @@ -150,12 +149,12 @@ class DecodeTests: XCTestCase { func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) } // MARK: Signature verification @@ -169,7 +168,7 @@ class DecodeTests: XCTestCase { func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testMatchesAnyAlgorithm() { From 087e6e71f35c02cc722492650e76063e25c22628 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 09:02:39 +0200 Subject: [PATCH 093/127] refactor: Move payload deseriaisation to decoder --- Sources/JWT/CompactJSONDecoder.swift | 15 +++++++++++++++ Sources/JWT/Decode.swift | 13 ++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Sources/JWT/CompactJSONDecoder.swift b/Sources/JWT/CompactJSONDecoder.swift index 0606395..bb353d5 100644 --- a/Sources/JWT/CompactJSONDecoder.swift +++ b/Sources/JWT/CompactJSONDecoder.swift @@ -1,3 +1,5 @@ +import Foundation + class CompactJSONDecoder: JSONDecoder { override func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable { guard let string = String(data: data, encoding: .ascii) else { @@ -14,4 +16,17 @@ class CompactJSONDecoder: JSONDecoder { return try super.decode(type, from: decoded) } + + func decode(from string: String) throws -> Payload { + guard let decoded = base64decode(string) else { + throw InvalidToken.decodeError("Payload is not correctly encoded as base64") + } + + let object = try JSONSerialization.jsonObject(with: decoded) + guard let payload = object as? Payload else { + throw InvalidToken.decodeError("Invalid payload") + } + + return payload + } } diff --git a/Sources/JWT/Decode.swift b/Sources/JWT/Decode.swift index c04bad6..5bfa569 100644 --- a/Sources/JWT/Decode.swift +++ b/Sources/JWT/Decode.swift @@ -90,22 +90,13 @@ func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signa let decoder = CompactJSONDecoder() let header = try decoder.decode(JOSEHeader.self, from: headerSegment) - - let payloadData = base64decode(payloadSegment) - if payloadData == nil { - throw InvalidToken.decodeError("Payload is not correctly encoded as base64") - } - - let payload = (try? JSONSerialization.jsonObject(with: payloadData!, options: JSONSerialization.ReadingOptions(rawValue: 0))) as? Payload - if payload == nil { - throw InvalidToken.decodeError("Invalid payload") - } + let payload = try decoder.decode(from: payloadSegment) guard let signature = base64decode(signatureSegment) else { throw InvalidToken.decodeError("Signature is not correctly encoded as base64") } - return (header: header, payload: ClaimSet(claims: payload!), signature: signature, signatureInput: signatureInput) + return (header: header, payload: ClaimSet(claims: payload), signature: signature, signatureInput: signatureInput) } // MARK: Signature Verification From f60df5b2bdd5963e55adbc030394cfcd54c447b6 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 09:05:26 +0200 Subject: [PATCH 094/127] refactor: Move encoding to compact encoder --- Sources/JWT/CompactJSONEncoder.swift | 8 ++++++++ Sources/JWT/Encode.swift | 10 +--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/JWT/CompactJSONEncoder.swift b/Sources/JWT/CompactJSONEncoder.swift index c3e454f..f759453 100644 --- a/Sources/JWT/CompactJSONEncoder.swift +++ b/Sources/JWT/CompactJSONEncoder.swift @@ -6,4 +6,12 @@ class CompactJSONEncoder: JSONEncoder { func encodeString(_ value: T) throws -> String { return base64encode(try super.encode(value)) } + + func encodeString(_ value: [String: Any]) -> String? { + if let data = try? JSONSerialization.data(withJSONObject: value) { + return base64encode(data) + } + + return nil + } } diff --git a/Sources/JWT/Encode.swift b/Sources/JWT/Encode.swift index 3c5bb68..0aaf196 100644 --- a/Sources/JWT/Encode.swift +++ b/Sources/JWT/Encode.swift @@ -8,14 +8,6 @@ import Foundation public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: String]? = nil) -> String { let encoder = CompactJSONEncoder() - func encodeJSON(_ payload: [String: Any]) -> String? { - if let data = try? JSONSerialization.data(withJSONObject: payload) { - return base64encode(data) - } - - return nil - } - var headers = headers ?? [:] if !headers.keys.contains("typ") { headers["typ"] = "JWT" @@ -23,7 +15,7 @@ public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: Str headers["alg"] = algorithm.description let header = try! encoder.encodeString(headers) - let payload = encodeJSON(claims.claims)! + let payload = encoder.encodeString(claims.claims)! let signingInput = "\(header).\(payload)" let signature = algorithm.sign(signingInput) return "\(signingInput).\(signature)" From d55e7b7fde24dd0fec3daba49689de44629ea1cd Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 13 Oct 2017 09:37:10 +0200 Subject: [PATCH 095/127] chore: Update CI to Swift 4 The library no longer supports Swift 3 in this version. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 41fcf91..c7f1e9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ os: language: generic sudo: required dist: trusty -osx_image: xcode8.3 +osx_image: xcode9 env: -- SWIFT_VERSION=3.1.1 +- SWIFT_VERSION=4.0 install: - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"; fi - git submodule update --init --recursive From 9045d647eec6f37b6d536243e3ad02c9a12411e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Hern=C3=A1ndez?= Date: Thu, 2 Nov 2017 17:58:57 +0100 Subject: [PATCH 096/127] fix(project): Add missing files to macOS, tvOS, watchOS targets (#94) --- JWT.xcodeproj/project.pbxproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj index 3d926c3..6c895b0 100644 --- a/JWT.xcodeproj/project.pbxproj +++ b/JWT.xcodeproj/project.pbxproj @@ -42,6 +42,12 @@ 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; 279D63AF1AD07FFF0024E2BC /* JWTDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */; }; + 501BF92F1FAB05AE00449B76 /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; + 501BF9301FAB05C500449B76 /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; + 501BF9311FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; + 501BF9321FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; + 501BF9331FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; + 501BF9341FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; 520A71171C469F010005C709 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; 520A71181C469F010005C709 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; @@ -499,12 +505,14 @@ 271E10811F90253300B5033C /* JWA.swift in Sources */, 273011171F34029900219C35 /* HMACCommonCrypto.swift in Sources */, CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, + 501BF92F1FAB05AE00449B76 /* CompactJSONEncoder.swift in Sources */, CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, 277794111DF22D0D00573F3E /* Encode.swift in Sources */, 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, 273011001F33EABA00219C35 /* HMAC.swift in Sources */, + 501BF9301FAB05C500449B76 /* CompactJSONDecoder.swift in Sources */, CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -516,12 +524,14 @@ 271E10821F90253300B5033C /* JWA.swift in Sources */, 273011181F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, + 501BF9311FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */, CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, 277794121DF22D0D00573F3E /* Encode.swift in Sources */, 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, 273011011F33EABA00219C35 /* HMAC.swift in Sources */, + 501BF9331FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */, CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -533,12 +543,14 @@ 271E10831F90253300B5033C /* JWA.swift in Sources */, 273011191F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, + 501BF9321FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */, CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, 277794131DF22D0D00573F3E /* Encode.swift in Sources */, 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */, 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, 273011021F33EABA00219C35 /* HMAC.swift in Sources */, + 501BF9341FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */, CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 36f4ee0e60faa0068c1a8290d25f4428e67a56c0 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 31 Jan 2018 00:39:41 +0000 Subject: [PATCH 097/127] chore(ci): Allow CocoaPods warnings The warning is usually about not supplying the Swift version. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c7f1e9e..20995c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,4 +16,4 @@ script: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-iOS build -sdk iphonesimulator; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-tvOS build -sdk appletvsimulator; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-watchOS build -sdk watchsimulator; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint --allow-warnings; fi From e2052f2ab8afdeaa564c17c8368948b3fe899f0a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 31 Jan 2018 00:44:50 +0000 Subject: [PATCH 098/127] fix: Build error caused when Foundation is not present By default when building via Xcode Foundation does not need to be imported --- Sources/JWT/CompactJSONEncoder.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/JWT/CompactJSONEncoder.swift b/Sources/JWT/CompactJSONEncoder.swift index f759453..2e4a10c 100644 --- a/Sources/JWT/CompactJSONEncoder.swift +++ b/Sources/JWT/CompactJSONEncoder.swift @@ -1,3 +1,6 @@ +import Foundation + + class CompactJSONEncoder: JSONEncoder { override func encode(_ value: T) throws -> Data { return try encodeString(value).data(using: .ascii) ?? Data() From b7188dc07c5a66267e67a7d87ba77ee009e2ddd8 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 31 Jan 2018 00:49:22 +0000 Subject: [PATCH 099/127] fix: Upgrade to CryptoSwift 0.8.0 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 707de2f..240d007 100644 --- a/Package.swift +++ b/Package.swift @@ -15,7 +15,7 @@ let package = Package( let package = Package( name: "JWT", dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0, minor: 6), + .Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0, minor: 8), ], exclude: [ "Sources/JWT/HMACCommonCrypto.swift", From d9a419a18a689cb0d8b263348b73f5ef28562f76 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 7 Feb 2018 09:14:23 +0000 Subject: [PATCH 100/127] docs: Always force unwrap the known valid UTF8 key Closes #101 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce1db66..0874ddd 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ claims.issuer = "fuller.li" claims.issuedAt = Date() claims["custom"] = "Hi" -JWT.encode(claims: claims, algorithm: .hs256("secret".data(using: .utf8))) +JWT.encode(claims: claims, algorithm: .hs256("secret".data(using: .utf8)!)) ``` #### Building a JWT with the builder pattern From 9d057e72ec4829e5403e22587dc4a61347accdcc Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 7 Feb 2018 21:21:56 +0000 Subject: [PATCH 101/127] feat: Extract algorithms to JWA --- JSONWebToken.podspec | 7 ++- Package.swift | 37 +++++++++------ Sources/JWA/HMAC/HMAC.swift | 36 ++++++++++++++ Sources/JWA/HMAC/HMACCommonCrypto.swift | 48 +++++++++++++++++++ Sources/JWA/HMAC/HMACCryptoSwift.swift | 32 +++++++++++++ Sources/JWA/JWA.swift | 32 +++++++++++++ Sources/JWA/None.swift | 15 ++++++ Sources/JWT/Algorithm.swift | 36 ++++++++++++++ Sources/JWT/Decode.swift | 2 +- Sources/JWT/Encode.swift | 3 +- Sources/JWT/HMAC.swift | 7 --- Sources/JWT/HMACCommonCrypto.swift | 46 ------------------ Sources/JWT/HMACCryptoSwift.swift | 28 ----------- Sources/JWT/JWA.swift | 57 ---------------------- Tests/JWATests/HMACTests.swift | 63 +++++++++++++++++++++++++ Tests/JWATests/NoneTests.swift | 23 +++++++++ 16 files changed, 316 insertions(+), 156 deletions(-) create mode 100644 Sources/JWA/HMAC/HMAC.swift create mode 100644 Sources/JWA/HMAC/HMACCommonCrypto.swift create mode 100644 Sources/JWA/HMAC/HMACCryptoSwift.swift create mode 100644 Sources/JWA/JWA.swift create mode 100644 Sources/JWA/None.swift create mode 100644 Sources/JWT/Algorithm.swift delete mode 100644 Sources/JWT/HMAC.swift delete mode 100644 Sources/JWT/HMACCommonCrypto.swift delete mode 100644 Sources/JWT/HMACCryptoSwift.swift delete mode 100644 Sources/JWT/JWA.swift create mode 100644 Tests/JWATests/HMACTests.swift create mode 100644 Tests/JWATests/NoneTests.swift diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec index 3ce74ef..1d0094d 100644 --- a/JSONWebToken.podspec +++ b/JSONWebToken.podspec @@ -6,14 +6,17 @@ Pod::Spec.new do |spec| spec.license = { :type => 'BSD', :file => 'LICENSE' } spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git', :tag => "#{spec.version}" } - spec.source_files = 'Sources/JWT/*.swift' + spec.source_files = [ + 'Sources/JWA/HMAC/*.swift', + 'Sources/{JWA,JWT}/*.swift', + ] spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.tvos.deployment_target = '9.0' spec.watchos.deployment_target = '2.0' spec.requires_arc = true spec.module_name = 'JWT' - spec.exclude_files = ['Sources/JWT/HMACCryptoSwift.swift'] + spec.exclude_files = ['Sources/JWA/HMAC/HMACCryptoSwift.swift'] if ARGV.include?('lint') spec.pod_target_xcconfig = { diff --git a/Package.swift b/Package.swift index 240d007..5ba29b4 100644 --- a/Package.swift +++ b/Package.swift @@ -1,24 +1,33 @@ +// swift-tools-version:4.0 + import PackageDescription #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) -let package = Package( - name: "JWT", - dependencies: [ - .Package(url: "https://github.com/kylef-archive/CommonCrypto.git", majorVersion: 1), - ], - exclude: [ - "Sources/JWT/HMACCryptoSwift.swift", - ] -) +let dependencies = [ + Package.Dependency.package(url: "https://github.com/kylef-archive/CommonCrypto.git", from: "1.0.0"), +] +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"), +] +let excludes = ["HMAC/HMACCommonCrypto.swift"] +let targetDependencies: [Target.Dependency] = ["CryptoSwift"] +#endif + + let package = Package( name: "JWT", - dependencies: [ - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0, minor: 8), + products: [ + .library(name: "JWT", targets: ["JWT"]), ], - exclude: [ - "Sources/JWT/HMACCommonCrypto.swift", + dependencies: dependencies, + targets: [ + .target(name: "JWA", dependencies: targetDependencies, exclude: excludes), + .target(name: "JWT", dependencies: ["JWA"]), + .testTarget(name: "JWATests", dependencies: ["JWA"]), + .testTarget(name: "JWTTests", dependencies: ["JWT"]), ] ) -#endif diff --git a/Sources/JWA/HMAC/HMAC.swift b/Sources/JWA/HMAC/HMAC.swift new file mode 100644 index 0000000..9252a03 --- /dev/null +++ b/Sources/JWA/HMAC/HMAC.swift @@ -0,0 +1,36 @@ +import Foundation + + +final public class HMACAlgorithm: Algorithm { + public let key: Data + public let hash: Hash + + public enum Hash { + case sha256 + case sha384 + case sha512 + } + + public init(key: Data, hash: Hash) { + self.key = key + self.hash = hash + } + + public init?(key: String, hash: Hash) { + guard let key = key.data(using: .utf8) else { return nil } + + self.key = key + self.hash = hash + } + + public var name: String { + switch hash { + case .sha256: + return "HS256" + case .sha384: + return "HS384" + case .sha512: + return "HS512" + } + } +} diff --git a/Sources/JWA/HMAC/HMACCommonCrypto.swift b/Sources/JWA/HMAC/HMACCommonCrypto.swift new file mode 100644 index 0000000..299fd8a --- /dev/null +++ b/Sources/JWA/HMAC/HMACCommonCrypto.swift @@ -0,0 +1,48 @@ +import Foundation +import CommonCrypto + + +extension HMACAlgorithm: SignAlgorithm, VerifyAlgorithm { + public func sign(_ message: Data) -> Data { + let context = UnsafeMutablePointer.allocate(capacity: 1) + defer { context.deallocate(capacity: 1) } + + key.withUnsafeBytes() { (buffer: UnsafePointer) in + CCHmacInit(context, hash.commonCryptoAlgorithm, buffer, size_t(key.count)) + } + + message.withUnsafeBytes { (buffer: UnsafePointer) in + CCHmacUpdate(context, buffer, size_t(message.count)) + } + + var hmac = Array(repeating: 0, count: Int(hash.commonCryptoDigestLength)) + CCHmacFinal(context, &hmac) + + return Data(hmac) + } +} + + +extension HMACAlgorithm.Hash { + var commonCryptoAlgorithm: CCHmacAlgorithm { + switch self { + case .sha256: + return CCHmacAlgorithm(kCCHmacAlgSHA256) + case .sha384: + return CCHmacAlgorithm(kCCHmacAlgSHA384) + case .sha512: + return CCHmacAlgorithm(kCCHmacAlgSHA512) + } + } + + var commonCryptoDigestLength: Int32 { + switch self { + case .sha256: + return CC_SHA256_DIGEST_LENGTH + case .sha384: + return CC_SHA384_DIGEST_LENGTH + case .sha512: + return CC_SHA512_DIGEST_LENGTH + } + } +} diff --git a/Sources/JWA/HMAC/HMACCryptoSwift.swift b/Sources/JWA/HMAC/HMACCryptoSwift.swift new file mode 100644 index 0000000..6153049 --- /dev/null +++ b/Sources/JWA/HMAC/HMACCryptoSwift.swift @@ -0,0 +1,32 @@ +import Foundation +import CryptoSwift + + +extension HMACAlgorithm: SignAlgorithm, VerifyAlgorithm { + public func sign(_ message: Data) -> Data { + let mac = HMAC(key: key.bytes, variant: hash.cryptoSwiftVariant) + + let result: [UInt8] + do { + result = try mac.authenticate(message.bytes) + } catch { + result = [] + } + + return Data(bytes: result) + } +} + + +extension HMACAlgorithm.Hash { + var cryptoSwiftVariant: HMAC.Variant { + switch self { + case .sha256: + return .sha256 + case .sha384: + return .sha384 + case .sha512: + return .sha512 + } + } +} diff --git a/Sources/JWA/JWA.swift b/Sources/JWA/JWA.swift new file mode 100644 index 0000000..2e02f7d --- /dev/null +++ b/Sources/JWA/JWA.swift @@ -0,0 +1,32 @@ +import Foundation + + +/// Represents a JSON Web Algorithm (JWA) +/// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 +public protocol Algorithm: class { + var name: String { get } +} + + +// MARK: Signing + +/// Represents a JSON Web Algorithm (JWA) that is capable of signing +public protocol SignAlgorithm: Algorithm { + func sign(_ message: Data) -> Data +} + + +// MARK: Verifying + +/// Represents a JSON Web Algorithm (JWA) that is capable of verifying +public protocol VerifyAlgorithm: Algorithm { + func verify(_ message: Data, signature: Data) -> Bool +} + + +extension SignAlgorithm { + /// Verify a signature for a message using the algorithm + public func verify(_ message: Data, signature: Data) -> Bool { + return sign(message) == signature + } +} diff --git a/Sources/JWA/None.swift b/Sources/JWA/None.swift new file mode 100644 index 0000000..26a238d --- /dev/null +++ b/Sources/JWA/None.swift @@ -0,0 +1,15 @@ +import Foundation + + +/// No Algorithm, i-e, insecure +public final class NoneAlgorithm: Algorithm, SignAlgorithm, VerifyAlgorithm { + public var name: String { + return "none" + } + + public init() {} + + public func sign(_ message: Data) -> Data { + return Data() + } +} diff --git a/Sources/JWT/Algorithm.swift b/Sources/JWT/Algorithm.swift new file mode 100644 index 0000000..f1d1e91 --- /dev/null +++ b/Sources/JWT/Algorithm.swift @@ -0,0 +1,36 @@ +import Foundation +import JWA + + +/// Represents a JSON Web Algorithm (JWA) +/// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 +public enum Algorithm: CustomStringConvertible { + /// No Algorithm, i-e, insecure + case none + + /// HMAC using SHA-256 hash algorithm + case hs256(Data) + + /// HMAC using SHA-384 hash algorithm + case hs384(Data) + + /// HMAC using SHA-512 hash algorithm + case hs512(Data) + + var algorithm: SignAlgorithm { + switch self { + case .none: + return NoneAlgorithm() + case .hs256(let key): + return HMACAlgorithm(key: key, hash: .sha256) + case .hs384(let key): + return HMACAlgorithm(key: key, hash: .sha384) + case .hs512(let key): + return HMACAlgorithm(key: key, hash: .sha512) + } + } + + public var description: String { + return algorithm.name + } +} diff --git a/Sources/JWT/Decode.swift b/Sources/JWT/Decode.swift index 5bfa569..0e2b6d0 100644 --- a/Sources/JWT/Decode.swift +++ b/Sources/JWT/Decode.swift @@ -108,7 +108,7 @@ func verifySignature(_ algorithms: [Algorithm], header: JOSEHeader, signingInput let verifiedAlgorithms = algorithms .filter { algorithm in algorithm.description == alg } - .filter { algorithm in algorithm.verify(signingInput, signature: signature) } + .filter { algorithm in algorithm.algorithm.verify(signingInput.data(using: .utf8)!, signature: signature) } if verifiedAlgorithms.isEmpty { throw InvalidToken.invalidAlgorithm diff --git a/Sources/JWT/Encode.swift b/Sources/JWT/Encode.swift index 0aaf196..643c827 100644 --- a/Sources/JWT/Encode.swift +++ b/Sources/JWT/Encode.swift @@ -1,5 +1,6 @@ import Foundation + /*** Encode a set of claims - parameter claims: The set of claims - parameter algorithm: The algorithm to sign the payload with @@ -17,7 +18,7 @@ public func encode(claims: ClaimSet, algorithm: Algorithm, headers: [String: Str let header = try! encoder.encodeString(headers) let payload = encoder.encodeString(claims.claims)! let signingInput = "\(header).\(payload)" - let signature = algorithm.sign(signingInput) + let signature = base64encode(algorithm.algorithm.sign(signingInput.data(using: .utf8)!)) return "\(signingInput).\(signature)" } diff --git a/Sources/JWT/HMAC.swift b/Sources/JWT/HMAC.swift deleted file mode 100644 index 2e9c66a..0000000 --- a/Sources/JWT/HMAC.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -enum HMACAlgorithm { - case sha256 - case sha384 - case sha512 -} diff --git a/Sources/JWT/HMACCommonCrypto.swift b/Sources/JWT/HMACCommonCrypto.swift deleted file mode 100644 index a144ccb..0000000 --- a/Sources/JWT/HMACCommonCrypto.swift +++ /dev/null @@ -1,46 +0,0 @@ -import Foundation -import CommonCrypto - - -extension HMACAlgorithm { - var commonCryptoAlgorithm: CCHmacAlgorithm { - switch self { - case .sha256: - return CCHmacAlgorithm(kCCHmacAlgSHA256) - case .sha384: - return CCHmacAlgorithm(kCCHmacAlgSHA384) - case .sha512: - return CCHmacAlgorithm(kCCHmacAlgSHA512) - } - } - - var commonCryptoDigestLength: Int32 { - switch self { - case .sha256: - return CC_SHA256_DIGEST_LENGTH - case .sha384: - return CC_SHA384_DIGEST_LENGTH - case .sha512: - return CC_SHA512_DIGEST_LENGTH - } - } -} - - -func hmac(algorithm: HMACAlgorithm, key: Data, message: Data) -> Data { - let context = UnsafeMutablePointer.allocate(capacity: 1) - defer { context.deallocate(capacity: 1) } - - key.withUnsafeBytes() { (buffer: UnsafePointer) in - CCHmacInit(context, algorithm.commonCryptoAlgorithm, buffer, size_t(key.count)) - } - - message.withUnsafeBytes { (buffer: UnsafePointer) in - CCHmacUpdate(context, buffer, size_t(message.count)) - } - - var hmac = Array(repeating: 0, count: Int(algorithm.commonCryptoDigestLength)) - CCHmacFinal(context, &hmac) - - return Data(hmac) -} diff --git a/Sources/JWT/HMACCryptoSwift.swift b/Sources/JWT/HMACCryptoSwift.swift deleted file mode 100644 index 401a803..0000000 --- a/Sources/JWT/HMACCryptoSwift.swift +++ /dev/null @@ -1,28 +0,0 @@ -import Foundation -import CryptoSwift - - -extension HMACAlgorithm { - var cryptoSwiftVariant: HMAC.Variant { - switch self { - case .sha256: - return .sha256 - case .sha384: - return .sha384 - case .sha512: - return .sha512 - } - } -} - - -func hmac(algorithm: HMACAlgorithm, key: Data, message: Data) -> Data { - let mac = HMAC(key: key.bytes, variant: algorithm.cryptoSwiftVariant) - let result: [UInt8] - do { - result = try mac.authenticate(message.bytes) - } catch { - result = [] - } - return Data(bytes: result) -} diff --git a/Sources/JWT/JWA.swift b/Sources/JWT/JWA.swift deleted file mode 100644 index 3ac9cef..0000000 --- a/Sources/JWT/JWA.swift +++ /dev/null @@ -1,57 +0,0 @@ -import Foundation - -/// Represents a JSON Web Algorithm (JWA) -/// https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 -public enum Algorithm: CustomStringConvertible { - /// No Algorithm, i-e, insecure - case none - - /// HMAC using SHA-256 hash algorithm - case hs256(Data) - - /// HMAC using SHA-384 hash algorithm - case hs384(Data) - - /// HMAC using SHA-512 hash algorithm - case hs512(Data) - - public var description: String { - switch self { - case .none: - return "none" - case .hs256: - return "HS256" - case .hs384: - return "HS384" - case .hs512: - return "HS512" - } - } - - /// Sign a message using the algorithm - func sign(_ message: String) -> String { - func signHS(_ key: Data, algorithm: HMACAlgorithm) -> String { - let messageData = message.data(using: String.Encoding.utf8, allowLossyConversion: false)! - return base64encode(hmac(algorithm: algorithm, key: key, message: messageData)) - } - - switch self { - case .none: - return "" - - case .hs256(let key): - return signHS(key, algorithm: .sha256) - - case .hs384(let key): - return signHS(key, algorithm: .sha384) - - case .hs512(let key): - return signHS(key, algorithm: .sha512) - } - } - - /// Verify a signature for a message using the algorithm - func verify(_ message: String, signature: Data) -> Bool { - return sign(message) == base64encode(signature) - } -} diff --git a/Tests/JWATests/HMACTests.swift b/Tests/JWATests/HMACTests.swift new file mode 100644 index 0000000..2991630 --- /dev/null +++ b/Tests/JWATests/HMACTests.swift @@ -0,0 +1,63 @@ +import Foundation +import XCTest +import JWA + + +class HMACAlgorithmTests: XCTestCase { + let key = "secret".data(using: .utf8)! + let message = "message".data(using: .utf8)! + let sha256Signature = Data(base64Encoded: "i19IcCmVwVmMVz2x4hhmqbgl1KeU0WnXBgoDYFeWNgs=")! + let sha384Signature = Data(base64Encoded: "rQ706A2kJ7KjPURXyXK/dZ9Qdm+7ZlaQ1Qt8s43VIX21Wck+p8vuSOKuGltKr9NL")! + let sha512Signature = Data(base64Encoded: "G7pYfHMO7box9Tq7C2ylieCd5OiU7kVeYUCAc5l1mtqvoGnux8AWR7sXPcsX9V0ir0mhgHG3SMXC7df3qCnGMg==")! + + // MARK: Name + + func testSHA256Name() { + let algorithm = HMACAlgorithm(key: key, hash: .sha256) + XCTAssertEqual(algorithm.name, "HS256") + } + + func testSHA384Name() { + let algorithm = HMACAlgorithm(key: key, hash: .sha384) + XCTAssertEqual(algorithm.name, "HS384") + } + + func testSHA512Name() { + let algorithm = HMACAlgorithm(key: key, hash: .sha512) + XCTAssertEqual(algorithm.name, "HS512") + } + + // MARK: Signing + + func testSHA256Sign() { + let algorithm = HMACAlgorithm(key: key, hash: .sha256) + XCTAssertEqual(algorithm.sign(message), sha256Signature) + } + + func testSHA384Sign() { + let algorithm = HMACAlgorithm(key: key, hash: .sha384) + XCTAssertEqual(algorithm.sign(message), sha384Signature) + } + + func testSHA512Sign() { + let algorithm = HMACAlgorithm(key: key, hash: .sha512) + XCTAssertEqual(algorithm.sign(message), sha512Signature) + } + + // MARK: Verify + + func testSHA256Verify() { + let algorithm = HMACAlgorithm(key: key, hash: .sha256) + XCTAssertTrue(algorithm.verify(message, signature: sha256Signature)) + } + + func testSHA384Verify() { + let algorithm = HMACAlgorithm(key: key, hash: .sha384) + XCTAssertTrue(algorithm.verify(message, signature: sha384Signature)) + } + + func testSHA512Verify() { + let algorithm = HMACAlgorithm(key: key, hash: .sha512) + XCTAssertTrue(algorithm.verify(message, signature: sha512Signature)) + } +} diff --git a/Tests/JWATests/NoneTests.swift b/Tests/JWATests/NoneTests.swift new file mode 100644 index 0000000..c3987c5 --- /dev/null +++ b/Tests/JWATests/NoneTests.swift @@ -0,0 +1,23 @@ +import XCTest +import JWA + + +class NoneAlgorithmTests: XCTestCase { + let message = "message".data(using: .utf8)! + let signature = Data() + + func testName() { + let algorithm = NoneAlgorithm() + XCTAssertEqual(algorithm.name, "none") + } + + func testSign() { + let algorithm = NoneAlgorithm() + XCTAssertEqual(algorithm.sign(message), signature) + } + + func testVerify() { + let algorithm = NoneAlgorithm() + XCTAssertTrue(algorithm.verify(message, signature: signature)) + } +} From 614d37e04453c956c7243fe977a49a6551b605a4 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 7 Feb 2018 21:49:21 +0000 Subject: [PATCH 102/127] chore: Remove Xcode Project for now Not possible to keep this in-sync during development, maybe restored in future --- .travis.yml | 10 +- JSONWebToken.podspec | 32 - JWT.xcodeproj/project.pbxproj | 921 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/JWT-OSX.xcscheme | 115 --- .../xcshareddata/xcschemes/JWT-iOS.xcscheme | 82 -- .../xcshareddata/xcschemes/JWT-tvOS.xcscheme | 82 -- .../xcschemes/JWT-watchOS.xcscheme | 82 -- JWT/Info.plist | 28 - JWT/JWT.h | 17 - 10 files changed, 5 insertions(+), 1371 deletions(-) delete mode 100644 JSONWebToken.podspec delete mode 100644 JWT.xcodeproj/project.pbxproj delete mode 100644 JWT.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme delete mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme delete mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme delete mode 100644 JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme delete mode 100644 JWT/Info.plist delete mode 100644 JWT/JWT.h diff --git a/.travis.yml b/.travis.yml index 20995c2..cbcea7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,8 @@ install: - git submodule update --init --recursive script: - swift test -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-OSX test -sdk macosx; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-iOS build -sdk iphonesimulator; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-tvOS build -sdk appletvsimulator; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-watchOS build -sdk watchsimulator; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint --allow-warnings; fi +#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-OSX test -sdk macosx; fi +#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-iOS build -sdk iphonesimulator; fi +#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-tvOS build -sdk appletvsimulator; fi +#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-watchOS build -sdk watchsimulator; fi +#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint --allow-warnings; fi diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec deleted file mode 100644 index 1d0094d..0000000 --- a/JSONWebToken.podspec +++ /dev/null @@ -1,32 +0,0 @@ -Pod::Spec.new do |spec| - spec.name = 'JSONWebToken' - spec.version = '2.2.0' - spec.summary = 'Swift library for JSON Web Tokens (JWT).' - spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' - spec.license = { :type => 'BSD', :file => 'LICENSE' } - spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } - spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git', :tag => "#{spec.version}" } - spec.source_files = [ - 'Sources/JWA/HMAC/*.swift', - 'Sources/{JWA,JWT}/*.swift', - ] - spec.ios.deployment_target = '8.0' - spec.osx.deployment_target = '10.9' - spec.tvos.deployment_target = '9.0' - spec.watchos.deployment_target = '2.0' - spec.requires_arc = true - spec.module_name = 'JWT' - spec.exclude_files = ['Sources/JWA/HMAC/HMACCryptoSwift.swift'] - - if ARGV.include?('lint') - spec.pod_target_xcconfig = { - 'SWIFT_INCLUDE_PATHS' => Dir.pwd, - } - else - spec.pod_target_xcconfig = { - 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/JSONWebToken/', - } - end - - spec.preserve_paths = 'CommonCrypto/{shim.h,module.modulemap}' -end diff --git a/JWT.xcodeproj/project.pbxproj b/JWT.xcodeproj/project.pbxproj deleted file mode 100644 index 6c895b0..0000000 --- a/JWT.xcodeproj/project.pbxproj +++ /dev/null @@ -1,921 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 271E10801F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; - 271E10811F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; - 271E10821F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; - 271E10831F90253300B5033C /* JWA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E107F1F90253300B5033C /* JWA.swift */; }; - 271E10891F90334B00B5033C /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; - 271E108B1F9034B100B5033C /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; - 271E108D1F9041C400B5033C /* CompactJSONDecoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */; }; - 271E108F1F9042E900B5033C /* CompactJSONEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */; }; - 271E10911F90488700B5033C /* JWTEncodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10901F90488700B5033C /* JWTEncodeTests.swift */; }; - 271E10931F9049A400B5033C /* PayloadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10921F9049A400B5033C /* PayloadTests.swift */; }; - 271E10951F9049E200B5033C /* ClaimSetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10941F9049E200B5033C /* ClaimSetTests.swift */; }; - 271E10971F904A0700B5033C /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10961F904A0700B5033C /* IntegrationTests.swift */; }; - 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; - 273011001F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; - 273011011F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; - 273011021F33EABA00219C35 /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273010FE1F33EABA00219C35 /* HMAC.swift */; }; - 273011161F34029900219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; - 273011171F34029900219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; - 273011181F34029A00219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; - 273011191F34029A00219C35 /* HMACCommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */; }; - 277794051DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; - 277794061DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; - 277794071DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; - 277794081DF221F800573F3E /* ClaimSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277794041DF221F800573F3E /* ClaimSet.swift */; }; - 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; - 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; - 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; - 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940A1DF22BE400573F3E /* JOSEHeader.swift */; }; - 277794101DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; - 277794111DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; - 277794121DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; - 277794131DF22D0D00573F3E /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2777940F1DF22D0D00573F3E /* Encode.swift */; }; - 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; }; - 279D63AF1AD07FFF0024E2BC /* JWTDecodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */; }; - 501BF92F1FAB05AE00449B76 /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; - 501BF9301FAB05C500449B76 /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; - 501BF9311FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; - 501BF9321FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */; }; - 501BF9331FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; - 501BF9341FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */; }; - 520A71171C469F010005C709 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; - 520A71181C469F010005C709 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; - 520A71191C469F010005C709 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; - 520A711A1C469F010005C709 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; - CD9B62171C7753D8005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; - CD9B62181C7753D8005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; - CD9B62191C7753D8005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; - CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; - CD9B621E1C7753D8005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CD9B62291C7753EC005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; - CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; - CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; - CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; - CD9B62301C7753EC005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71141C469F010005C709 /* Claims.swift */; }; - CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71161C469F010005C709 /* JWT.swift */; }; - CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71151C469F010005C709 /* Decode.swift */; }; - CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520A71131C469F010005C709 /* Base64.swift */; }; - CD9B62421C7753FB005D4844 /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = 279D63A11AD07FFF0024E2BC /* JWT.h */; settings = {ATTRIBUTES = (Public, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 279D63A91AD07FFF0024E2BC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 279D63931AD07FFF0024E2BC /* Project object */; - proxyType = 1; - remoteGlobalIDString = 279D639B1AD07FFF0024E2BC; - remoteInfo = JWT; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 271E107F1F90253300B5033C /* JWA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWA.swift; sourceTree = ""; }; - 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONEncoder.swift; sourceTree = ""; }; - 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoder.swift; sourceTree = ""; }; - 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONDecoderTests.swift; sourceTree = ""; }; - 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactJSONEncoderTests.swift; sourceTree = ""; }; - 271E10901F90488700B5033C /* JWTEncodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTEncodeTests.swift; sourceTree = ""; }; - 271E10921F9049A400B5033C /* PayloadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayloadTests.swift; sourceTree = ""; }; - 271E10941F9049E200B5033C /* ClaimSetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClaimSetTests.swift; sourceTree = ""; }; - 271E10961F904A0700B5033C /* IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = ""; }; - 273010FE1F33EABA00219C35 /* HMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; - 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCommonCrypto.swift; sourceTree = ""; }; - 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACCryptoSwift.swift; sourceTree = ""; }; - 277794041DF221F800573F3E /* ClaimSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClaimSet.swift; sourceTree = ""; }; - 2777940A1DF22BE400573F3E /* JOSEHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JOSEHeader.swift; sourceTree = ""; }; - 2777940F1DF22D0D00573F3E /* Encode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Encode.swift; sourceTree = ""; }; - 279D639C1AD07FFF0024E2BC /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 279D63A01AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 279D63A11AD07FFF0024E2BC /* JWT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JWT.h; sourceTree = ""; }; - 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JWTTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 279D63AD1AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTDecodeTests.swift; sourceTree = ""; }; - 520A71131C469F010005C709 /* Base64.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base64.swift; sourceTree = ""; }; - 520A71141C469F010005C709 /* Claims.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Claims.swift; sourceTree = ""; }; - 520A71151C469F010005C709 /* Decode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decode.swift; sourceTree = ""; }; - 520A71161C469F010005C709 /* JWT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = ""; }; - 520A711B1C469F440005C709 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; - 540942F3614C41E3827F2013 /* Pods_JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CD9B62231C7753D8005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CD9B62351C7753EC005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CD9B62471C7753FB005D4844 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWTTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 279D63981AD07FFF0024E2BC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 279D63A41AD07FFF0024E2BC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B621B1C7753D8005D4844 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B622D1C7753EC005D4844 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B623F1C7753FB005D4844 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 271E10861F902D8900B5033C /* JWT */ = { - isa = PBXGroup; - children = ( - 277794041DF221F800573F3E /* ClaimSet.swift */, - 2777940A1DF22BE400573F3E /* JOSEHeader.swift */, - 271E10881F90334B00B5033C /* CompactJSONEncoder.swift */, - 271E108A1F9034B100B5033C /* CompactJSONDecoder.swift */, - 520A71131C469F010005C709 /* Base64.swift */, - 520A71141C469F010005C709 /* Claims.swift */, - 520A71151C469F010005C709 /* Decode.swift */, - 2777940F1DF22D0D00573F3E /* Encode.swift */, - 520A71161C469F010005C709 /* JWT.swift */, - 271E107F1F90253300B5033C /* JWA.swift */, - 273010FE1F33EABA00219C35 /* HMAC.swift */, - 273011041F33FC5F00219C35 /* HMACCommonCrypto.swift */, - 273011091F33FC9100219C35 /* HMACCryptoSwift.swift */, - ); - path = JWT; - sourceTree = ""; - }; - 279D63921AD07FFF0024E2BC = { - isa = PBXGroup; - children = ( - 520A711B1C469F440005C709 /* Package.swift */, - 520A71121C469F010005C709 /* Sources */, - 279D639E1AD07FFF0024E2BC /* Sources */, - 279D63AB1AD07FFF0024E2BC /* Tests */, - 279D639D1AD07FFF0024E2BC /* Products */, - AC8AE547FDAF3DD80EB4DB2F /* Frameworks */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 279D639D1AD07FFF0024E2BC /* Products */ = { - isa = PBXGroup; - children = ( - 279D639C1AD07FFF0024E2BC /* JWT.framework */, - 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */, - CD9B62231C7753D8005D4844 /* JWT.framework */, - CD9B62351C7753EC005D4844 /* JWT.framework */, - CD9B62471C7753FB005D4844 /* JWT.framework */, - ); - name = Products; - sourceTree = ""; - }; - 279D639E1AD07FFF0024E2BC /* Sources */ = { - isa = PBXGroup; - children = ( - 279D63A11AD07FFF0024E2BC /* JWT.h */, - 279D639F1AD07FFF0024E2BC /* Supporting Files */, - ); - name = Sources; - path = JWT; - sourceTree = ""; - }; - 279D639F1AD07FFF0024E2BC /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 279D63A01AD07FFF0024E2BC /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 279D63AB1AD07FFF0024E2BC /* Tests */ = { - isa = PBXGroup; - children = ( - 271E108C1F9041C400B5033C /* CompactJSONDecoderTests.swift */, - 271E108E1F9042E900B5033C /* CompactJSONEncoderTests.swift */, - 271E10941F9049E200B5033C /* ClaimSetTests.swift */, - 271E10921F9049A400B5033C /* PayloadTests.swift */, - 271E10901F90488700B5033C /* JWTEncodeTests.swift */, - 279D63AE1AD07FFF0024E2BC /* JWTDecodeTests.swift */, - 271E10961F904A0700B5033C /* IntegrationTests.swift */, - 279D63AC1AD07FFF0024E2BC /* Supporting Files */, - ); - name = Tests; - path = Tests/JWTTests; - sourceTree = ""; - }; - 279D63AC1AD07FFF0024E2BC /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 279D63AD1AD07FFF0024E2BC /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 520A71121C469F010005C709 /* Sources */ = { - isa = PBXGroup; - children = ( - 271E10861F902D8900B5033C /* JWT */, - ); - path = Sources; - sourceTree = ""; - }; - AC8AE547FDAF3DD80EB4DB2F /* Frameworks */ = { - isa = PBXGroup; - children = ( - 540942F3614C41E3827F2013 /* Pods_JWT.framework */, - CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 279D63991AD07FFF0024E2BC /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 279D63A21AD07FFF0024E2BC /* JWT.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B621D1C7753D8005D4844 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - CD9B621E1C7753D8005D4844 /* JWT.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B622F1C7753EC005D4844 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - CD9B62301C7753EC005D4844 /* JWT.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B62411C7753FB005D4844 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - CD9B62421C7753FB005D4844 /* JWT.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 279D639B1AD07FFF0024E2BC /* JWT-OSX */ = { - isa = PBXNativeTarget; - buildConfigurationList = 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT-OSX" */; - buildPhases = ( - 279D63971AD07FFF0024E2BC /* Sources */, - 279D63981AD07FFF0024E2BC /* Frameworks */, - 279D63991AD07FFF0024E2BC /* Headers */, - 66725DA11C591D9800FC32F4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "JWT-OSX"; - productName = JWT; - productReference = 279D639C1AD07FFF0024E2BC /* JWT.framework */; - productType = "com.apple.product-type.framework"; - }; - 279D63A61AD07FFF0024E2BC /* JWTTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 279D63B51AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWTTests" */; - buildPhases = ( - 279D63A31AD07FFF0024E2BC /* Sources */, - 279D63A41AD07FFF0024E2BC /* Frameworks */, - 279D63A51AD07FFF0024E2BC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 279D63AA1AD07FFF0024E2BC /* PBXTargetDependency */, - ); - name = JWTTests; - productName = JWTTests; - productReference = 279D63A71AD07FFF0024E2BC /* JWTTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - CD9B62131C7753D8005D4844 /* JWT-iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = CD9B62201C7753D8005D4844 /* Build configuration list for PBXNativeTarget "JWT-iOS" */; - buildPhases = ( - CD9B62161C7753D8005D4844 /* Sources */, - CD9B621B1C7753D8005D4844 /* Frameworks */, - CD9B621D1C7753D8005D4844 /* Headers */, - CD9B621F1C7753D8005D4844 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "JWT-iOS"; - productName = JWT; - productReference = CD9B62231C7753D8005D4844 /* JWT.framework */; - productType = "com.apple.product-type.framework"; - }; - CD9B62251C7753EC005D4844 /* JWT-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = CD9B62321C7753EC005D4844 /* Build configuration list for PBXNativeTarget "JWT-tvOS" */; - buildPhases = ( - CD9B62281C7753EC005D4844 /* Sources */, - CD9B622D1C7753EC005D4844 /* Frameworks */, - CD9B622F1C7753EC005D4844 /* Headers */, - CD9B62311C7753EC005D4844 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "JWT-tvOS"; - productName = JWT; - productReference = CD9B62351C7753EC005D4844 /* JWT.framework */; - productType = "com.apple.product-type.framework"; - }; - CD9B62371C7753FB005D4844 /* JWT-watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = CD9B62441C7753FB005D4844 /* Build configuration list for PBXNativeTarget "JWT-watchOS" */; - buildPhases = ( - CD9B623A1C7753FB005D4844 /* Sources */, - CD9B623F1C7753FB005D4844 /* Frameworks */, - CD9B62411C7753FB005D4844 /* Headers */, - CD9B62431C7753FB005D4844 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "JWT-watchOS"; - productName = JWT; - productReference = CD9B62471C7753FB005D4844 /* JWT.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 279D63931AD07FFF0024E2BC /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftMigration = 0700; - LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0910; - ORGANIZATIONNAME = Cocode; - TargetAttributes = { - 279D639B1AD07FFF0024E2BC = { - CreatedOnToolsVersion = 6.2; - }; - 279D63A61AD07FFF0024E2BC = { - CreatedOnToolsVersion = 6.2; - }; - }; - }; - buildConfigurationList = 279D63961AD07FFF0024E2BC /* Build configuration list for PBXProject "JWT" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 279D63921AD07FFF0024E2BC; - productRefGroup = 279D639D1AD07FFF0024E2BC /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 279D639B1AD07FFF0024E2BC /* JWT-OSX */, - CD9B62131C7753D8005D4844 /* JWT-iOS */, - CD9B62251C7753EC005D4844 /* JWT-tvOS */, - CD9B62371C7753FB005D4844 /* JWT-watchOS */, - 279D63A61AD07FFF0024E2BC /* JWTTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 279D63A51AD07FFF0024E2BC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 66725DA11C591D9800FC32F4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B621F1C7753D8005D4844 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B62311C7753EC005D4844 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B62431C7753FB005D4844 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 279D63971AD07FFF0024E2BC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 271E10801F90253300B5033C /* JWA.swift in Sources */, - 273011161F34029900219C35 /* HMACCommonCrypto.swift in Sources */, - 520A71181C469F010005C709 /* Claims.swift in Sources */, - 271E10891F90334B00B5033C /* CompactJSONEncoder.swift in Sources */, - 520A711A1C469F010005C709 /* JWT.swift in Sources */, - 520A71191C469F010005C709 /* Decode.swift in Sources */, - 277794101DF22D0D00573F3E /* Encode.swift in Sources */, - 2777940B1DF22BE400573F3E /* JOSEHeader.swift in Sources */, - 277794051DF221F800573F3E /* ClaimSet.swift in Sources */, - 273010FF1F33EABA00219C35 /* HMAC.swift in Sources */, - 271E108B1F9034B100B5033C /* CompactJSONDecoder.swift in Sources */, - 520A71171C469F010005C709 /* Base64.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 279D63A31AD07FFF0024E2BC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 271E10971F904A0700B5033C /* IntegrationTests.swift in Sources */, - 271E108F1F9042E900B5033C /* CompactJSONEncoderTests.swift in Sources */, - 271E10911F90488700B5033C /* JWTEncodeTests.swift in Sources */, - 271E108D1F9041C400B5033C /* CompactJSONDecoderTests.swift in Sources */, - 279D63AF1AD07FFF0024E2BC /* JWTDecodeTests.swift in Sources */, - 271E10931F9049A400B5033C /* PayloadTests.swift in Sources */, - 271E10951F9049E200B5033C /* ClaimSetTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B62161C7753D8005D4844 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 271E10811F90253300B5033C /* JWA.swift in Sources */, - 273011171F34029900219C35 /* HMACCommonCrypto.swift in Sources */, - CD9B62171C7753D8005D4844 /* Claims.swift in Sources */, - 501BF92F1FAB05AE00449B76 /* CompactJSONEncoder.swift in Sources */, - CD9B62181C7753D8005D4844 /* JWT.swift in Sources */, - CD9B62191C7753D8005D4844 /* Decode.swift in Sources */, - 277794111DF22D0D00573F3E /* Encode.swift in Sources */, - 2777940C1DF22BE400573F3E /* JOSEHeader.swift in Sources */, - 277794061DF221F800573F3E /* ClaimSet.swift in Sources */, - 273011001F33EABA00219C35 /* HMAC.swift in Sources */, - 501BF9301FAB05C500449B76 /* CompactJSONDecoder.swift in Sources */, - CD9B621A1C7753D8005D4844 /* Base64.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B62281C7753EC005D4844 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 271E10821F90253300B5033C /* JWA.swift in Sources */, - 273011181F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, - CD9B62291C7753EC005D4844 /* Claims.swift in Sources */, - 501BF9311FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */, - CD9B622A1C7753EC005D4844 /* JWT.swift in Sources */, - CD9B622B1C7753EC005D4844 /* Decode.swift in Sources */, - 277794121DF22D0D00573F3E /* Encode.swift in Sources */, - 2777940D1DF22BE400573F3E /* JOSEHeader.swift in Sources */, - 277794071DF221F800573F3E /* ClaimSet.swift in Sources */, - 273011011F33EABA00219C35 /* HMAC.swift in Sources */, - 501BF9331FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */, - CD9B622C1C7753EC005D4844 /* Base64.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CD9B623A1C7753FB005D4844 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 271E10831F90253300B5033C /* JWA.swift in Sources */, - 273011191F34029A00219C35 /* HMACCommonCrypto.swift in Sources */, - CD9B623B1C7753FB005D4844 /* Claims.swift in Sources */, - 501BF9321FAB05E400449B76 /* CompactJSONEncoder.swift in Sources */, - CD9B623C1C7753FB005D4844 /* JWT.swift in Sources */, - CD9B623D1C7753FB005D4844 /* Decode.swift in Sources */, - 277794131DF22D0D00573F3E /* Encode.swift in Sources */, - 2777940E1DF22BE400573F3E /* JOSEHeader.swift in Sources */, - 277794081DF221F800573F3E /* ClaimSet.swift in Sources */, - 273011021F33EABA00219C35 /* HMAC.swift in Sources */, - 501BF9341FAB05E700449B76 /* CompactJSONDecoder.swift in Sources */, - CD9B623E1C7753FB005D4844 /* Base64.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 279D63AA1AD07FFF0024E2BC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 279D639B1AD07FFF0024E2BC /* JWT-OSX */; - targetProxy = 279D63A91AD07FFF0024E2BC /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 279D63B01AD07FFF0024E2BC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = "$(PROJECT_NAME)"; - SDKROOT = macosx; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 279D63B11AD07FFF0024E2BC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = "$(PROJECT_NAME)"; - SDKROOT = macosx; - SWIFT_INCLUDE_PATHS = "$(SRCROOT)"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 279D63B31AD07FFF0024E2BC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 279D63B41AD07FFF0024E2BC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; - 279D63B61AD07FFF0024E2BC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", - "$(inherited)", - ); - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = Tests/JWTTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 279D63B71AD07FFF0024E2BC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", - "$(inherited)", - ); - INFOPLIST_FILE = Tests/JWTTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - CD9B62211C7753D8005D4844 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - CD9B62221C7753D8005D4844 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - CD9B62331C7753EC005D4844 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; - }; - name = Debug; - }; - CD9B62341C7753EC005D4844 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - CD9B62451C7753FB005D4844 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - CD9B62461C7753FB005D4844 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = JWT/Info.plist; - INSTALL_PATH = "@rpath"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "org.cocode.$(PRODUCT_NAME:rfc1034identifier)"; - SDKROOT = watchos; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = 4; - VALIDATE_PRODUCT = YES; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 279D63961AD07FFF0024E2BC /* Build configuration list for PBXProject "JWT" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 279D63B01AD07FFF0024E2BC /* Debug */, - 279D63B11AD07FFF0024E2BC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT-OSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 279D63B31AD07FFF0024E2BC /* Debug */, - 279D63B41AD07FFF0024E2BC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 279D63B51AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWTTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 279D63B61AD07FFF0024E2BC /* Debug */, - 279D63B71AD07FFF0024E2BC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CD9B62201C7753D8005D4844 /* Build configuration list for PBXNativeTarget "JWT-iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CD9B62211C7753D8005D4844 /* Debug */, - CD9B62221C7753D8005D4844 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CD9B62321C7753EC005D4844 /* Build configuration list for PBXNativeTarget "JWT-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CD9B62331C7753EC005D4844 /* Debug */, - CD9B62341C7753EC005D4844 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CD9B62441C7753FB005D4844 /* Build configuration list for PBXNativeTarget "JWT-watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CD9B62451C7753FB005D4844 /* Debug */, - CD9B62461C7753FB005D4844 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 279D63931AD07FFF0024E2BC /* Project object */; -} diff --git a/JWT.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JWT.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index e3cefe8..0000000 --- a/JWT.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme deleted file mode 100644 index dc61530..0000000 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-OSX.xcscheme +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme deleted file mode 100644 index 387dbf8..0000000 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-iOS.xcscheme +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme deleted file mode 100644 index 46efb5f..0000000 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-tvOS.xcscheme +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme b/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme deleted file mode 100644 index c0bf55d..0000000 --- a/JWT.xcodeproj/xcshareddata/xcschemes/JWT-watchOS.xcscheme +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/JWT/Info.plist b/JWT/Info.plist deleted file mode 100644 index ba3fdf1..0000000 --- a/JWT/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2015 Cocode. All rights reserved. - NSPrincipalClass - - - diff --git a/JWT/JWT.h b/JWT/JWT.h deleted file mode 100644 index 1af30d5..0000000 --- a/JWT/JWT.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// JWT.h -// JWT -// -// Created by Kyle Fuller on 04/04/2015. -// Copyright (c) 2015 Cocode. All rights reserved. -// - -#import - -//! Project version number for JWT. -FOUNDATION_EXPORT double JWTVersionNumber; - -//! Project version string for JWT. -FOUNDATION_EXPORT const unsigned char JWTVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import From 20f2efeab560931e3c1700b02f72035736cde1ff Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 7 Feb 2018 22:12:35 +0000 Subject: [PATCH 103/127] chore: Restore building on all platforms using generated Xcode --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index cbcea7f..7674264 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,9 @@ install: - git submodule update --init --recursive script: - swift test -#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-OSX test -sdk macosx; fi -#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-iOS build -sdk iphonesimulator; fi -#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-tvOS build -sdk appletvsimulator; fi -#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-watchOS build -sdk watchsimulator; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then swift package generate-xcodeproj; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk macosx; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk iphonesimulator; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk appletvsimulator; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk watchsimulator; fi #- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint --allow-warnings; fi From 9f67977fd82c88b1aace2e861640a961d589bb83 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Wed, 7 Feb 2018 22:32:17 +0000 Subject: [PATCH 104/127] chore: Refactor Travis to use build matrix --- .travis.yml | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7674264..225f25f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,44 @@ os: -- linux -- osx + - osx + - linux +osx_image: xcode9 language: generic sudo: required dist: trusty -osx_image: xcode9 env: -- SWIFT_VERSION=4.0 + global: + - SWIFT_VERSION=4.0 + matrix: + - SWIFTPM_BUILD=true + - SWIFTPM_TEST=true + - XCODE_TEST_SDK=macosx + - XCODE_BUILD_SDK=iphonesimulator + - XCODE_BUILD_SDK=appletvsimulator + - XCODE_BUILD_SDK=watchsimulator + +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 + env: XCODE_BUILD_SDK=iphonesimulator + - os: linux + env: XCODE_BUILD_SDK=appletvsimulator + - os: linux + env: XCODE_BUILD_SDK=watchsimulator + install: -- if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"; fi -- git submodule update --init --recursive + - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" + script: -- swift test -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then swift package generate-xcodeproj; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk macosx; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk iphonesimulator; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk appletvsimulator; fi -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk watchsimulator; fi -#- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then pod lib lint --allow-warnings; fi +- 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 +- if [ -n "$XCODE_TEST_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk $XCODE_TEST_SDK; fi From 7f422516b1be5fae8dc5888185f4ddb7bea12dfb Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 17:21:23 -0500 Subject: [PATCH 105/127] Remove CommonCrypto directory as Swift 4.2 no longer requires this --- CommonCrypto/module.modulemap | 4 ---- CommonCrypto/shim.h | 1 - Package.swift | 4 +--- 3 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 CommonCrypto/module.modulemap delete mode 100644 CommonCrypto/shim.h diff --git a/CommonCrypto/module.modulemap b/CommonCrypto/module.modulemap deleted file mode 100644 index b70f7d6..0000000 --- a/CommonCrypto/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ -module CommonCrypto [system] { - header "shim.h" - export * -} diff --git a/CommonCrypto/shim.h b/CommonCrypto/shim.h deleted file mode 100644 index c332624..0000000 --- a/CommonCrypto/shim.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Package.swift b/Package.swift index 5ba29b4..7b5d1f1 100644 --- a/Package.swift +++ b/Package.swift @@ -4,9 +4,7 @@ import PackageDescription #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) -let dependencies = [ - Package.Dependency.package(url: "https://github.com/kylef-archive/CommonCrypto.git", from: "1.0.0"), -] +let dependencies: [Package.Dependency] = [] let excludes = ["HMAC/HMACCryptoSwift.swift"] let targetDependencies: [Target.Dependency] = [] #else From 800490657dc81ea1c22a46bcd94226d3337214c3 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 17:59:06 -0500 Subject: [PATCH 106/127] Correct encoding unit tests to account for unordered Swift dictionaries --- Tests/JWTTests/JWTEncodeTests.swift | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Tests/JWTTests/JWTEncodeTests.swift b/Tests/JWTTests/JWTEncodeTests.swift index 0dbb7b3..08882a2 100644 --- a/Tests/JWTTests/JWTEncodeTests.swift +++ b/Tests/JWTTests/JWTEncodeTests.swift @@ -23,14 +23,36 @@ class JWTEncodeTests: XCTestCase { 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"]) + + 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" + ] - XCTAssertEqual(jwt, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IngifQ.e30.ddEotxYYMMdat5HPgYFQnkHRdPXsxPG71ooyhIUoqGA") + XCTAssertTrue(expected.contains(jwt)) } } From 398c8254d3f0e75a067a3ac57526135545da4f45 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 18:27:09 -0500 Subject: [PATCH 107/127] Reindent to match existing style --- Tests/JWTTests/JWTEncodeTests.swift | 62 ++++++++++++++--------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Tests/JWTTests/JWTEncodeTests.swift b/Tests/JWTTests/JWTEncodeTests.swift index 08882a2..9ff7f14 100644 --- a/Tests/JWTTests/JWTEncodeTests.swift +++ b/Tests/JWTTests/JWTEncodeTests.swift @@ -6,53 +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" } - - let expected = [ - // { "alg": "HS256", "typ": "JWT" } - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ", - // { "typ": "JWT", "alg": "HS256" } - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.x5Fdll-kZBImOPtpT1fZH_8hDW01Ax3pbZx_EiljoLk" - ] - - XCTAssertTrue(expected.contains(jwt)) + + 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"]) - - 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" - ] - + + 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)) } } From ec735aa8e5516f698540c013b57b4628a9ab9ffc Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 18:30:37 -0500 Subject: [PATCH 108/127] Fix warning about deallocate(capacity:) deprecation --- Sources/JWA/HMAC/HMACCommonCrypto.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)) From 264a622ddd48523a0827dc7932203a57902f41b2 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 18:44:21 -0500 Subject: [PATCH 109/127] Update many unit tests to stop using deprecated decode method --- Tests/JWTTests/JWTDecodeTests.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index 24a17b3..3876301 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -18,7 +18,7 @@ class DecodeTests: XCTestCase { } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - XCTAssertThrowsError(try decode("a.b", algorithm: .none), "Not enough segments") + XCTAssertThrowsError(try decode("a.b", algorithm: .none) as ClaimSet, "Not enough segments") } // MARK: Disable verify @@ -39,24 +39,24 @@ class DecodeTests: XCTestCase { func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org") as ClaimSet) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li") as ClaimSet) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) } func testUnexpiredClaim() throws { @@ -99,7 +99,7 @@ class DecodeTests: XCTestCase { func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) } // MARK: Issued at claim @@ -121,7 +121,7 @@ class DecodeTests: XCTestCase { func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) } func testInvalidIssuedAtClaim() { @@ -149,12 +149,12 @@ class DecodeTests: XCTestCase { func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine") as ClaimSet) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle") as ClaimSet) } // MARK: Signature verification @@ -168,7 +168,7 @@ class DecodeTests: XCTestCase { func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) } func testMatchesAnyAlgorithm() { From 61e4cd73a19c957c52a407c6d99cd5ac378566de Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 19:01:34 -0500 Subject: [PATCH 110/127] Fix remaining unit tests --- Tests/JWTTests/JWTDecodeTests.swift | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index 3876301..cc4bf6d 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -1,6 +1,6 @@ import Foundation import XCTest -import JWT +@testable import JWT class DecodeTests: XCTestCase { func testDecodingValidJWTAsClaimSet() throws { @@ -93,7 +93,7 @@ class DecodeTests: XCTestCase { func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)), error: "Not before claim (nbf) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet, error: "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { @@ -134,7 +134,7 @@ class DecodeTests: XCTestCase { func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine") as ClaimSet) { payload in XCTAssertEqual(payload.count, 1) XCTAssertEqual(payload["aud"] as! [String], ["maxine", "katie"]) } @@ -142,7 +142,7 @@ class DecodeTests: XCTestCase { func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle") as ClaimSet) { payload in XCTAssertEqual(payload as! [String: String], ["aud": "kyle"]) } } @@ -161,7 +161,7 @@ class DecodeTests: XCTestCase { func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(try decode(jwt, algorithm: .none)) { payload in + assertSuccess(try decode(jwt, algorithm: .none) as ClaimSet) { payload in XCTAssertEqual(payload as! [String: String], ["test": "ing"]) } } @@ -173,36 +173,36 @@ class DecodeTests: XCTestCase { func testMatchesAnyAlgorithm() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." - assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret".data(using: .utf8)!), .hs256("secret".data(using: .utf8)!)])) + assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret".data(using: .utf8)!), .hs256("secret".data(using: .utf8)!)]) as ClaimSet) } func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" - assertSuccess(try decode(jwt, algorithm: .hs384("secret".data(using: .utf8)!))) { payload in + assertSuccess(try decode(jwt, algorithm: .hs384("secret".data(using: .utf8)!)) as ClaimSet) { payload in XCTAssertEqual(payload as! [String: String], ["some": "payload"]) } } 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)!)) as ClaimSet) { 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 +213,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): From 14ddad4a6ca570757dbcf22fbd32451dfbe3f1d0 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 19:14:45 -0500 Subject: [PATCH 111/127] Bump CryptoSwift to 0.10.0 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 7b5d1f1..7461b1a 100644 --- a/Package.swift +++ b/Package.swift @@ -9,7 +9,7 @@ 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"] From 2ab9490a71f94ed8b1700cd42af478af186bc848 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 19:27:44 -0500 Subject: [PATCH 112/127] Correct misspelled method name for validateExpiry(leeway:), retain old method name as a deprecated method --- Sources/JWT/ClaimSet.swift | 9 +++++++-- Tests/JWTTests/ClaimSetTests.swift | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Sources/JWT/ClaimSet.swift b/Sources/JWT/ClaimSet.swift index 114c04e..08eeb9f 100644 --- a/Sources/JWT/ClaimSet.swift +++ b/Sources/JWT/ClaimSet.swift @@ -104,7 +104,7 @@ extension ClaimSet { try validateAudience(audience) } - try validateExpiary(leeway: leeway) + try validateExpiry(leeway: leeway) try validateNotBefore(leeway: leeway) try validateIssuedAt(leeway: leeway) } @@ -132,8 +132,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/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.") } From 312dce7d8007673275841b3f249f26210a3514b5 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 19:42:38 -0500 Subject: [PATCH 113/127] Remove deprecated encode/decode methods --- Sources/JWT/Decode.swift | 12 ------ Sources/JWT/Encode.swift | 11 ------ Tests/JWTTests/JWTDecodeTests.swift | 59 +++++++++++++---------------- 3 files changed, 26 insertions(+), 56 deletions(-) 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/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index cc4bf6d..313b000 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -3,29 +3,22 @@ import XCTest @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") } func testFailsToDecodeInvalidStringWithoutThreeSegments() { - XCTAssertThrowsError(try decode("a.b", algorithm: .none) as ClaimSet, "Not enough segments") + XCTAssertThrowsError(try decode("a.b", algorithm: .none), "Not enough segments") } // MARK: Disable verify 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,37 +26,37 @@ 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") } func testIncorrectIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org") as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org")) } func testMissingIssuerValidation() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li") as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) } // MARK: Expiration claim func testExpiredClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testInvalidExpiaryClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testUnexpiredClaim() throws { // 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)!)) + let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) } @@ -71,7 +64,7 @@ class DecodeTests: XCTestCase { // 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,26 +73,26 @@ 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) } func testInvalidNotBeforeClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOlsxNDI4MTg5NzIwXX0.PUL1FQubzzJa4MNXe2D3d5t5cMaqFr3kYlzRUzly-C8" - assertDecodeError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet, error: "Not before claim (nbf) must be an integer") + assertDecodeError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)), error: "Not before claim (nbf) must be an integer") } func testUnmetNotBeforeClaim() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } // MARK: Issued at claim @@ -107,21 +100,21 @@ 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) } func testIssuedAtClaimInTheFuture() { // If this just started failing, hello 2024! let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testInvalidIssuedAtClaim() { @@ -134,7 +127,7 @@ class DecodeTests: XCTestCase { func testAudiencesClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibWF4aW5lIiwia2F0aWUiXX0.-PKvdNLCClrWG7CvesHP6PB0-vxu-_IZcsYhJxBy5JM" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine") as ClaimSet) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) { payload in XCTAssertEqual(payload.count, 1) XCTAssertEqual(payload["aud"] as! [String], ["maxine", "katie"]) } @@ -142,50 +135,50 @@ class DecodeTests: XCTestCase { func testAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.dpgH4JOwueReaBoanLSxsGTc7AjKUvo7_M1sAfy_xVE" - assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle") as ClaimSet) { payload in + assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) { payload in XCTAssertEqual(payload as! [String: String], ["aud": "kyle"]) } } func testMismatchAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine") as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine")) } func testMissingAudienceClaim() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w" - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle") as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle")) } // MARK: Signature verification func testNoneAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - assertSuccess(try decode(jwt, algorithm: .none) as ClaimSet) { payload in + assertSuccess(try decode(jwt, algorithm: .none)) { payload in XCTAssertEqual(payload as! [String: String], ["test": "ing"]) } } func testNoneFailsWithSecretAlgorithm() { let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0." - XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) as ClaimSet) + XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) } func testMatchesAnyAlgorithm() { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w." - assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret".data(using: .utf8)!), .hs256("secret".data(using: .utf8)!)]) as ClaimSet) + assertFailure(try decode(jwt, algorithms: [.hs256("anothersecret".data(using: .utf8)!), .hs256("secret".data(using: .utf8)!)])) } func testHS384Algorithm() { let jwt = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.lddiriKLoo42qXduMhCTKZ5Lo3njXxOC92uXyvbLyYKzbq4CVVQOb3MpDwnI19u4" - assertSuccess(try decode(jwt, algorithm: .hs384("secret".data(using: .utf8)!)) as ClaimSet) { payload in + assertSuccess(try decode(jwt, algorithm: .hs384("secret".data(using: .utf8)!))) { payload in XCTAssertEqual(payload as! [String: String], ["some": "payload"]) } } func testHS512Algorithm() { let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA" - assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!)) as ClaimSet) { claims in + assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { claims in XCTAssertEqual(claims as! [String: String], ["some": "payload"]) } } From 30677dfbb1c473b87ea55bc3775fed1fb6b3f5a7 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 20:14:48 -0500 Subject: [PATCH 114/127] Undo removal of CommonCrypto; will try to find compatible solution between Swift 4.0 and 4.2 --- CommonCrypto/module.modulemap | 4 ++++ CommonCrypto/shim.h | 1 + Package.swift | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 CommonCrypto/module.modulemap create mode 100644 CommonCrypto/shim.h diff --git a/CommonCrypto/module.modulemap b/CommonCrypto/module.modulemap new file mode 100644 index 0000000..b70f7d6 --- /dev/null +++ b/CommonCrypto/module.modulemap @@ -0,0 +1,4 @@ +module CommonCrypto [system] { + header "shim.h" + export * +} diff --git a/CommonCrypto/shim.h b/CommonCrypto/shim.h new file mode 100644 index 0000000..c332624 --- /dev/null +++ b/CommonCrypto/shim.h @@ -0,0 +1 @@ +#include diff --git a/Package.swift b/Package.swift index 7461b1a..36bc2f2 100644 --- a/Package.swift +++ b/Package.swift @@ -4,7 +4,9 @@ import PackageDescription #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) -let dependencies: [Package.Dependency] = [] +let dependencies = [ + Package.Dependency.package(url: "https://github.com/kylef-archive/CommonCrypto.git", from: "1.0.0"), +] let excludes = ["HMAC/HMACCryptoSwift.swift"] let targetDependencies: [Target.Dependency] = [] #else From 662871d1b9a4c4ba2642ac6f08237ecfed4b5dd0 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 21:33:46 -0500 Subject: [PATCH 115/127] see if stripping down the Travis config gets builds working on macOS at least --- .travis.yml | 86 ++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/.travis.yml b/.travis.yml index 225f25f..701dcfa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,44 +1,48 @@ -os: - - osx - - linux -osx_image: xcode9 -language: generic -sudo: required -dist: trusty -env: - global: - - SWIFT_VERSION=4.0 - matrix: - - SWIFTPM_BUILD=true - - SWIFTPM_TEST=true - - XCODE_TEST_SDK=macosx - - XCODE_BUILD_SDK=iphonesimulator - - XCODE_BUILD_SDK=appletvsimulator - - XCODE_BUILD_SDK=watchsimulator +os: osx +osx_image: xcode9.4 +script: swift build -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 - env: XCODE_BUILD_SDK=iphonesimulator - - os: linux - env: XCODE_BUILD_SDK=appletvsimulator - - os: linux - env: XCODE_BUILD_SDK=watchsimulator +# os: +# - osx +# - linux +# osx_image: xcode9 +# language: generic +# sudo: required +# dist: trusty +# env: +# global: +# - SWIFT_VERSION=4.0 +# matrix: +# - SWIFTPM_BUILD=true +# - SWIFTPM_TEST=true +# - XCODE_TEST_SDK=macosx +# - XCODE_BUILD_SDK=iphonesimulator +# - XCODE_BUILD_SDK=appletvsimulator +# - XCODE_BUILD_SDK=watchsimulator -install: - - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" +# 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 +# env: XCODE_BUILD_SDK=iphonesimulator +# - os: linux +# env: XCODE_BUILD_SDK=appletvsimulator +# - os: linux +# env: XCODE_BUILD_SDK=watchsimulator -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 -- if [ -n "$XCODE_TEST_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk $XCODE_TEST_SDK; fi +# 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 +# - if [ -n "$XCODE_TEST_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk $XCODE_TEST_SDK; fi From 47a8b7f6f8c0523202f9d468eab1b0dd69b26fdf Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 21:44:27 -0500 Subject: [PATCH 116/127] try adding Ubuntu back into Travis builds --- .travis.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 701dcfa..a50c6e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,20 @@ -os: osx +os: + - osx + - linux osx_image: xcode9.4 script: swift build +language: generic +sudo: required +dist: xenial + +env: + global: + - SWIFT_VERSION=4.1.2 + +install: + - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" +script: + - swift build # os: # - osx @@ -10,8 +24,6 @@ script: swift build # sudo: required # dist: trusty # env: -# global: -# - SWIFT_VERSION=4.0 # matrix: # - SWIFTPM_BUILD=true # - SWIFTPM_TEST=true From 11351084b4cd4eb7a9558b5c109ab5be361fccb5 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 22:20:33 -0500 Subject: [PATCH 117/127] =?UTF-8?q?Travis=20doesn=E2=80=99t=20support=20Xe?= =?UTF-8?q?nial,=20back=20to=20Trusty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a50c6e2..8d4abdd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ osx_image: xcode9.4 script: swift build language: generic sudo: required -dist: xenial +dist: trusty env: global: From a50823d3c9c85a6f70fd162e7043610ca098a037 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 22:43:44 -0500 Subject: [PATCH 118/127] getting closer to original config --- .travis.yml | 69 +++++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d4abdd..6a5dca8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ os: - - osx - - linux + - osx + - linux osx_image: xcode9.4 -script: swift build language: generic sudo: required dist: trusty @@ -10,51 +9,37 @@ dist: trusty env: global: - SWIFT_VERSION=4.1.2 + matrix: + - SWIFTPM_BUILD=true + - SWIFTPM_TEST=true + - XCODE_TEST_SDK=macosx + - XCODE_BUILD_SDK=iphonesimulator + - XCODE_BUILD_SDK=appletvsimulator + - XCODE_BUILD_SDK=watchsimulator -install: - - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" -script: - - swift build - -# os: -# - osx -# - linux -# osx_image: xcode9 -# language: generic -# sudo: required -# dist: trusty -# env: -# matrix: -# - SWIFTPM_BUILD=true -# - SWIFTPM_TEST=true -# - XCODE_TEST_SDK=macosx -# - XCODE_BUILD_SDK=iphonesimulator -# - XCODE_BUILD_SDK=appletvsimulator -# - XCODE_BUILD_SDK=watchsimulator - -# matrix: -# exclude: +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 -# env: XCODE_BUILD_SDK=iphonesimulator -# - os: linux -# env: XCODE_BUILD_SDK=appletvsimulator -# - os: linux -# env: XCODE_BUILD_SDK=watchsimulator + - os: linux + env: XCODE_TEST_SDK=macosx + - os: linux + env: XCODE_BUILD_SDK=iphonesimulator + - os: linux + env: XCODE_BUILD_SDK=appletvsimulator + - os: linux + env: XCODE_BUILD_SDK=watchsimulator -# install: -# - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" +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 -# - if [ -n "$XCODE_TEST_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk $XCODE_TEST_SDK; fi +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 +- if [ -n "$XCODE_TEST_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package test -sdk $XCODE_TEST_SDK; fi From 44d6d594da50911cddf3792e004b48d11c5f4908 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 23:03:52 -0500 Subject: [PATCH 119/127] Sync up LinuxMain.swift (hopefully) --- Tests/LinuxMain.swift | 89 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 8488183..b12a121 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), @@ -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(CompactJSONDecoder.allTests), + testCase(CompactJSONEncoder.allTests), testCase(DecodeTests.allTests), + testCase(IntegrationTests.allTests), + testCase(JWTEncodeTests.allTests), testCase(PayloadTests.allTests), + testCase(ValidationTests.allTests) ]) From 32b7b6e5db2edd889bd9e3a6c2c2d15f1d42390b Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 23 Jul 2018 23:15:30 -0500 Subject: [PATCH 120/127] Fix LinuxMain.swift typo --- Tests/LinuxMain.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index b12a121..3f3b768 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -126,8 +126,8 @@ extension ValidationTests { XCTMain([ testCase(HMACAlgorithmTests.allTests), testCase(NoneAlgorithmTests.allTests), - testCase(CompactJSONDecoder.allTests), - testCase(CompactJSONEncoder.allTests), + testCase(CompactJSONDecoderTests.allTests), + testCase(CompactJSONEncoderTests.allTests), testCase(DecodeTests.allTests), testCase(IntegrationTests.allTests), testCase(JWTEncodeTests.allTests), From 65dfb1a9f61a76f55bb9c23ff272ed1443a954dc Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Tue, 24 Jul 2018 12:49:03 -0500 Subject: [PATCH 121/127] See if converting TimeInterval/Double to Int might help Travis builds pass --- Tests/JWTTests/JWTDecodeTests.swift | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index 313b000..adca9ab 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -57,7 +57,12 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) + + if let expirationClaim = claims.expiration?.timeIntervalSince1970 { + XCTAssertEqual(Int(expirationClaim), 1728188491) + } else { + XCTFail() + } } func testUnexpiredClaimString() throws { @@ -74,7 +79,11 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720) + if let notBeforeClaim = claims.notBefore?.timeIntervalSince1970 { + XCTAssertEqual(Int(notBeforeClaim), 1428189720) + } else { + XCTFail() + } } func testNotBeforeClaimString() throws { @@ -101,7 +110,11 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720) + if let issuedAtClaim = claims.issuedAt?.timeIntervalSince1970 { + XCTAssertEqual(Int(issuedAtClaim), 1428189720) + } else { + XCTFail() + } } func testIssuedAtClaimInThePastString() throws { From f2bbd1d8dbf2e53234f9d632c5a8808aaaf9b0db Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Tue, 24 Jul 2018 12:59:51 -0500 Subject: [PATCH 122/127] See if explicitly handling Ints in parsing JWT times fixes Ubuntu builds --- Sources/JWT/ClaimSet.swift | 5 +++++ Tests/JWTTests/JWTDecodeTests.swift | 19 +++---------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Sources/JWT/ClaimSet.swift b/Sources/JWT/ClaimSet.swift index 08eeb9f..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) diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index adca9ab..7cfe348 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -57,12 +57,7 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0" let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - - if let expirationClaim = claims.expiration?.timeIntervalSince1970 { - XCTAssertEqual(Int(expirationClaim), 1728188491) - } else { - XCTFail() - } + XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491) } func testUnexpiredClaimString() throws { @@ -79,11 +74,7 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs" let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - if let notBeforeClaim = claims.notBefore?.timeIntervalSince1970 { - XCTAssertEqual(Int(notBeforeClaim), 1428189720) - } else { - XCTFail() - } + XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720) } func testNotBeforeClaimString() throws { @@ -110,11 +101,7 @@ class DecodeTests: XCTestCase { let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4" let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)) - if let issuedAtClaim = claims.issuedAt?.timeIntervalSince1970 { - XCTAssertEqual(Int(issuedAtClaim), 1428189720) - } else { - XCTFail() - } + XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720) } func testIssuedAtClaimInThePastString() throws { From 4b83583095569f47751f97832f990933c113d7f8 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Tue, 24 Jul 2018 16:16:47 -0500 Subject: [PATCH 123/127] simplify Travis config to use swift test only swift test builds JWT and JWA, so compilation errors for those will otherwise just result in two jobs that fail for the same reason; one can still check the Travis output to see where exactly the failure is occurring --- .travis.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a5dca8..2c00dc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,9 @@ 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 @@ -19,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 @@ -38,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 From 708c7a75e38d689c27e6fec1b6bc18a251455559 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Tue, 24 Jul 2018 16:48:23 -0500 Subject: [PATCH 124/127] Correct misspelled unit test method name --- Tests/JWTTests/JWTDecodeTests.swift | 2 +- Tests/LinuxMain.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/JWTTests/JWTDecodeTests.swift b/Tests/JWTTests/JWTDecodeTests.swift index 7cfe348..cde1a10 100644 --- a/Tests/JWTTests/JWTDecodeTests.swift +++ b/Tests/JWTTests/JWTDecodeTests.swift @@ -47,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)!))) } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 3f3b768..492555b 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -54,7 +54,7 @@ extension DecodeTests { ("testIncorrectIssuerValidation", testIncorrectIssuerValidation), ("testMissingIssuerValidation", testMissingIssuerValidation), ("testExpiredClaim", testExpiredClaim), - ("testInvalidExpiaryClaim", testInvalidExpiaryClaim), + ("testInvalidExpiryClaim", testInvalidExpiryClaim), ("testUnexpiredClaim", testUnexpiredClaim), ("testUnexpiredClaimString", testUnexpiredClaimString), ("testNotBeforeClaim", testNotBeforeClaim), From 44f4b7a4ed7c1d2a165e106f2eb236ad199a54be Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Tue, 24 Jul 2018 17:41:02 -0500 Subject: [PATCH 125/127] Fix for CommonCrypto inclusion in Swift 4.2 --- Package.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Package.swift b/Package.swift index 36bc2f2..01b5e95 100644 --- a/Package.swift +++ b/Package.swift @@ -4,9 +4,13 @@ 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 From 898f0c8ef842134c585cd5d0bc5dc0eb5dd878ed Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 6 Aug 2018 19:11:16 -0500 Subject: [PATCH 126/127] Add podspec --- JSONWebToken.podspec | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 JSONWebToken.podspec diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec new file mode 100644 index 0000000..3e885ae --- /dev/null +++ b/JSONWebToken.podspec @@ -0,0 +1,32 @@ +Pod::Spec.new do |spec| + spec.name = 'JSONWebToken' + spec.version = '3.0.0' + spec.summary = 'Swift library for JSON Web Tokens (JWT).' + spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' + spec.license = { :type => 'BSD', :file => 'LICENSE' } + spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } + spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git' } + spec.source_files = 'Sources/JWT/*.swift', 'Build-Phases/common-crypto.sh' + spec.ios.deployment_target = '8.0' + spec.osx.deployment_target = '10.9' + spec.tvos.deployment_target = '9.0' + spec.watchos.deployment_target = '2.0' + spec.requires_arc = true + spec.module_name = 'JWT' + spec.exclude_files = ['Sources/JWT/HMACCryptoSwift.swift'] + + spec.swift_version = '4.0' + + if ARGV.include?('lint') + spec.pod_target_xcconfig = { + 'SWIFT_INCLUDE_PATHS' => Dir.pwd, + } + else + spec.pod_target_xcconfig = { + 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/JSONWebToken/', + } + end + + spec.preserve_paths = 'Build-Phases/*.sh' + spec.script_phase = { :name => 'CommonCrypto', :script => 'sh $SRCROOT/JSONWebToken/Build-Phases/common-crypto.sh', :execution_position => :before_compile } +end From 50b7757bec445b2bd2d2cccdfc18d2ade912d940 Mon Sep 17 00:00:00 2001 From: Jonathan Thornton Date: Mon, 6 Aug 2018 21:26:28 -0500 Subject: [PATCH 127/127] Delete JSONWebToken.podspec --- JSONWebToken.podspec | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 JSONWebToken.podspec diff --git a/JSONWebToken.podspec b/JSONWebToken.podspec deleted file mode 100644 index 3e885ae..0000000 --- a/JSONWebToken.podspec +++ /dev/null @@ -1,32 +0,0 @@ -Pod::Spec.new do |spec| - spec.name = 'JSONWebToken' - spec.version = '3.0.0' - spec.summary = 'Swift library for JSON Web Tokens (JWT).' - spec.homepage = 'https://github.com/kylef/JSONWebToken.swift' - spec.license = { :type => 'BSD', :file => 'LICENSE' } - spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } - spec.source = { :git => 'https://github.com/kylef/JSONWebToken.swift.git' } - spec.source_files = 'Sources/JWT/*.swift', 'Build-Phases/common-crypto.sh' - spec.ios.deployment_target = '8.0' - spec.osx.deployment_target = '10.9' - spec.tvos.deployment_target = '9.0' - spec.watchos.deployment_target = '2.0' - spec.requires_arc = true - spec.module_name = 'JWT' - spec.exclude_files = ['Sources/JWT/HMACCryptoSwift.swift'] - - spec.swift_version = '4.0' - - if ARGV.include?('lint') - spec.pod_target_xcconfig = { - 'SWIFT_INCLUDE_PATHS' => Dir.pwd, - } - else - spec.pod_target_xcconfig = { - 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/JSONWebToken/', - } - end - - spec.preserve_paths = 'Build-Phases/*.sh' - spec.script_phase = { :name => 'CommonCrypto', :script => 'sh $SRCROOT/JSONWebToken/Build-Phases/common-crypto.sh', :execution_position => :before_compile } -end