Skip to content

Commit 7154710

Browse files
committed
refactor: Use XCT for validating raising
1 parent 7187541 commit 7154710

File tree

2 files changed

+60
-59
lines changed

2 files changed

+60
-59
lines changed

Sources/JWT/ClaimSet.swift

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import Foundation
22

3+
func parseTimeInterval(_ value: Any?) -> Date? {
4+
guard let value = value else { return nil }
5+
6+
if let string = value as? String, let interval = TimeInterval(string) {
7+
return Date(timeIntervalSince1970: interval)
8+
}
9+
10+
if let interval = value as? TimeInterval {
11+
return Date(timeIntervalSince1970: interval)
12+
}
13+
14+
return nil
15+
}
16+
317
public struct ClaimSet {
418
var claims: [String: Any]
519

@@ -48,11 +62,7 @@ extension ClaimSet {
4862

4963
public var expiration: Date? {
5064
get {
51-
if let expiration = claims["exp"] as? TimeInterval {
52-
return Date(timeIntervalSince1970: expiration)
53-
}
54-
55-
return nil
65+
return parseTimeInterval(claims["exp"])
5666
}
5767

5868
set {
@@ -62,11 +72,7 @@ extension ClaimSet {
6272

6373
public var notBefore: Date? {
6474
get {
65-
if let notBefore = claims["nbf"] as? TimeInterval {
66-
return Date(timeIntervalSince1970: notBefore)
67-
}
68-
69-
return nil
75+
return parseTimeInterval(claims["nbf"])
7076
}
7177

7278
set {
@@ -76,11 +82,7 @@ extension ClaimSet {
7682

7783
public var issuedAt: Date? {
7884
get {
79-
if let issuedAt = claims["iat"] as? TimeInterval {
80-
return Date(timeIntervalSince1970: issuedAt)
81-
}
82-
83-
return nil
85+
return parseTimeInterval(claims["iat"])
8486
}
8587

8688
set {

Tests/JWTTests/JWTDecodeTests.swift

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,86 +10,85 @@ class DecodeTests: XCTestCase {
1010
XCTAssertEqual(claims["name"] as? String, "Kyle")
1111
}
1212

13-
func testDecodingValidJWT() {
13+
func testDecodingValidJWT() throws {
1414
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg"
1515

16-
assertSuccess(try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
17-
XCTAssertEqual(payload as! [String: String], ["name": "Kyle"])
18-
}
16+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
17+
XCTAssertEqual(claims["name"] as? String, "Kyle")
1918
}
2019

2120
func testFailsToDecodeInvalidStringWithoutThreeSegments() {
22-
assertDecodeError(try decode("a.b", algorithm: .none), error: "Not enough segments")
21+
XCTAssertThrowsError(try decode("a.b", algorithm: .none), "Not enough segments")
2322
}
2423

2524
// MARK: Disable verify
2625

27-
func testDisablingVerify() {
26+
func testDisablingVerify() throws {
2827
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w"
29-
assertSuccess(try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li"))
28+
_ = try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li") as ClaimSet
3029
}
3130

3231
// MARK: Issuer claim
3332

34-
func testSuccessfulIssuerValidation() {
33+
func testSuccessfulIssuerValidation() throws {
3534
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ"
36-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li")) { payload in
37-
XCTAssertEqual(payload as! [String: String], ["iss": "fuller.li"])
38-
}
35+
36+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
37+
XCTAssertEqual(claims.issuer, "fuller.li")
3938
}
4039

4140
func testIncorrectIssuerValidation() {
4241
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.wOhJ9_6lx-3JGJPmJmtFCDI3kt7uMAMmhHIslti7ryI"
43-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org"))
42+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "querykit.org"))
4443
}
4544

4645
func testMissingIssuerValidation() {
4746
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w"
48-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li"))
47+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), issuer: "fuller.li"))
4948
}
5049

5150
// MARK: Expiration claim
5251

5352
func testExpiredClaim() {
5453
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MjgxODg0OTF9.cy6b2szsNkKnHFnz2GjTatGjoHBTs8vBKnPGZgpp91I"
55-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
54+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
5655
}
5756

5857
func testInvalidExpiaryClaim() {
5958
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs"
60-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
59+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
6160
}
6261

63-
func testUnexpiredClaim() {
62+
func testUnexpiredClaim() throws {
6463
// If this just started failing, hello 2024!
6564
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0"
66-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
67-
XCTAssertEqual(payload as! [String: Int], ["exp": 1728188491])
68-
}
65+
66+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
67+
XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491)
6968
}
7069

71-
func testUnexpiredClaimString() {
70+
func testUnexpiredClaimString() throws {
7271
// If this just started failing, hello 2024!
7372
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk"
74-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
75-
XCTAssertEqual(payload as! [String: String], ["exp": "1728188491"])
76-
}
73+
74+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
75+
XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491)
7776
}
7877

7978
// MARK: Not before claim
8079

81-
func testNotBeforeClaim() {
80+
func testNotBeforeClaim() throws {
8281
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs"
83-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
84-
XCTAssertEqual(payload as! [String: Int], ["nbf": 1428189720])
85-
}
82+
83+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
84+
XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720)
8685
}
8786

88-
func testNotBeforeClaimString() {
87+
func testNotBeforeClaimString() throws {
8988
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI"
90-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
91-
XCTAssertEqual(payload as! [String: String], ["nbf": "1428189720"])
92-
}
89+
90+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
91+
XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720)
9392
}
9493

9594
func testInvalidNotBeforeClaim() {
@@ -100,29 +99,29 @@ class DecodeTests: XCTestCase {
10099
func testUnmetNotBeforeClaim() {
101100
// If this just started failing, hello 2024!
102101
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgxODg0OTF9.Tzhu1tu-7BXcF5YEIFFE1Vmg4tEybUnaz58FR4PcblQ"
103-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
102+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
104103
}
105104

106105
// MARK: Issued at claim
107106

108-
func testIssuedAtClaimInThePast() {
107+
func testIssuedAtClaimInThePast() throws {
109108
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4"
110-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
111-
XCTAssertEqual(payload as! [String: Int], ["iat": 1428189720])
112-
}
109+
110+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
111+
XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720)
113112
}
114113

115-
func testIssuedAtClaimInThePastString() {
114+
func testIssuedAtClaimInThePastString() throws {
116115
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k"
117-
assertSuccess(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))) { payload in
118-
XCTAssertEqual(payload as! [String: String], ["iat": "1428189720"])
119-
}
116+
117+
let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
118+
XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720)
120119
}
121120

122121
func testIssuedAtClaimInTheFuture() {
123122
// If this just started failing, hello 2024!
124123
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MjgxODg0OTF9.owHiJyJmTcW1lBW5y_Rz3iBfSbcNiXlbZ2fY9qR7-aU"
125-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
124+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
126125
}
127126

128127
func testInvalidIssuedAtClaim() {
@@ -150,12 +149,12 @@ class DecodeTests: XCTestCase {
150149

151150
func testMismatchAudienceClaim() {
152151
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJreWxlIn0.VEB_n06pTSLlTXPFkc46ARADJ9HXNUBUPo3VhL9RDe4" // kyle
153-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine"))
152+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "maxine"))
154153
}
155154

156155
func testMissingAudienceClaim() {
157156
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w"
158-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle"))
157+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!), audience: "kyle"))
159158
}
160159

161160
// MARK: Signature verification
@@ -169,7 +168,7 @@ class DecodeTests: XCTestCase {
169168

170169
func testNoneFailsWithSecretAlgorithm() {
171170
let jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ0ZXN0IjoiaW5nIn0."
172-
assertFailure(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
171+
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
173172
}
174173

175174
func testMatchesAnyAlgorithm() {

0 commit comments

Comments
 (0)