Parse JWT Header
This commit is contained in:
@@ -7,18 +7,15 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
821E160721D7ED3F00E2D71A /* TokenDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821E160621D7ED3F00E2D71A /* TokenDeserializer.swift */; };
|
||||||
82CAF46A21D7D41800FED241 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF46921D7D41800FED241 /* AppDelegate.swift */; };
|
82CAF46A21D7D41800FED241 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF46921D7D41800FED241 /* AppDelegate.swift */; };
|
||||||
82CAF46C21D7D41C00FED241 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 82CAF46B21D7D41C00FED241 /* Assets.xcassets */; };
|
82CAF46C21D7D41C00FED241 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 82CAF46B21D7D41C00FED241 /* Assets.xcassets */; };
|
||||||
82CAF46F21D7D41C00FED241 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 82CAF46D21D7D41C00FED241 /* MainMenu.xib */; };
|
82CAF46F21D7D41C00FED241 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 82CAF46D21D7D41C00FED241 /* MainMenu.xib */; };
|
||||||
82CAF47B21D7D41C00FED241 /* JotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF47A21D7D41C00FED241 /* JotTests.swift */; };
|
82CAF47B21D7D41C00FED241 /* JotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF47A21D7D41C00FED241 /* JotTests.swift */; };
|
||||||
82CAF48821D7D56D00FED241 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48721D7D56D00FED241 /* JWT.swift */; };
|
82CAF48821D7D56D00FED241 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48721D7D56D00FED241 /* JWT.swift */; };
|
||||||
82CAF48921D7D57700FED241 /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48721D7D56D00FED241 /* JWT.swift */; };
|
|
||||||
82CAF48B21D7D5B700FED241 /* Payload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48A21D7D5B700FED241 /* Payload.swift */; };
|
82CAF48B21D7D5B700FED241 /* Payload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48A21D7D5B700FED241 /* Payload.swift */; };
|
||||||
82CAF48D21D7D60100FED241 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48C21D7D60000FED241 /* Header.swift */; };
|
82CAF48D21D7D60100FED241 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48C21D7D60000FED241 /* Header.swift */; };
|
||||||
82CAF48F21D7D81800FED241 /* Signature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48E21D7D81800FED241 /* Signature.swift */; };
|
82CAF48F21D7D81800FED241 /* Signature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48E21D7D81800FED241 /* Signature.swift */; };
|
||||||
82CAF49021D7DC5100FED241 /* Payload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48A21D7D5B700FED241 /* Payload.swift */; };
|
|
||||||
82CAF49121D7DC5300FED241 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48C21D7D60000FED241 /* Header.swift */; };
|
|
||||||
82CAF49221D7DC5600FED241 /* Signature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF48E21D7D81800FED241 /* Signature.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -32,6 +29,7 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
821E160621D7ED3F00E2D71A /* TokenDeserializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenDeserializer.swift; sourceTree = "<group>"; };
|
||||||
82CAF46621D7D41800FED241 /* Jot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Jot.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
82CAF46621D7D41800FED241 /* Jot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Jot.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
82CAF46921D7D41800FED241 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
82CAF46921D7D41800FED241 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
82CAF46B21D7D41C00FED241 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
82CAF46B21D7D41C00FED241 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
@@ -113,6 +111,7 @@
|
|||||||
82CAF48A21D7D5B700FED241 /* Payload.swift */,
|
82CAF48A21D7D5B700FED241 /* Payload.swift */,
|
||||||
82CAF48C21D7D60000FED241 /* Header.swift */,
|
82CAF48C21D7D60000FED241 /* Header.swift */,
|
||||||
82CAF48E21D7D81800FED241 /* Signature.swift */,
|
82CAF48E21D7D81800FED241 /* Signature.swift */,
|
||||||
|
821E160621D7ED3F00E2D71A /* TokenDeserializer.swift */,
|
||||||
);
|
);
|
||||||
path = Token;
|
path = Token;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -224,6 +223,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
821E160721D7ED3F00E2D71A /* TokenDeserializer.swift in Sources */,
|
||||||
82CAF48D21D7D60100FED241 /* Header.swift in Sources */,
|
82CAF48D21D7D60100FED241 /* Header.swift in Sources */,
|
||||||
82CAF48B21D7D5B700FED241 /* Payload.swift in Sources */,
|
82CAF48B21D7D5B700FED241 /* Payload.swift in Sources */,
|
||||||
82CAF46A21D7D41800FED241 /* AppDelegate.swift in Sources */,
|
82CAF46A21D7D41800FED241 /* AppDelegate.swift in Sources */,
|
||||||
@@ -236,11 +236,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
82CAF49121D7DC5300FED241 /* Header.swift in Sources */,
|
|
||||||
82CAF49021D7DC5100FED241 /* Payload.swift in Sources */,
|
|
||||||
82CAF47B21D7D41C00FED241 /* JotTests.swift in Sources */,
|
82CAF47B21D7D41C00FED241 /* JotTests.swift in Sources */,
|
||||||
82CAF49221D7DC5600FED241 /* Signature.swift in Sources */,
|
|
||||||
82CAF48921D7D57700FED241 /* JWT.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@@ -23,7 +23,9 @@ enum JwtType: String, Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum SigningAlgorithm: String, Codable {
|
enum SigningAlgorithm: String, Codable {
|
||||||
case rsa = "RSA"
|
case rsa256 = "RS256"
|
||||||
case hmac = "HMAC"
|
case rsa384 = "RS384"
|
||||||
case ecdsa = "ECDSA"
|
case rsa512 = "RS512"
|
||||||
|
case hmac256 = "HM256"
|
||||||
|
case ecdsa256 = "ES256"
|
||||||
}
|
}
|
||||||
|
@@ -9,19 +9,13 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class JWT {
|
class JWT {
|
||||||
private let header: Header
|
let header: Header
|
||||||
private let payload: Payload
|
let payload: Payload
|
||||||
private let signature: Signature
|
let signature: Signature
|
||||||
|
|
||||||
init(header: Header, payload: Payload, signature: Signature) {
|
init(header: Header, payload: Payload, signature: Signature) {
|
||||||
self.header = header
|
self.header = header
|
||||||
self.payload = payload
|
self.payload = payload
|
||||||
self.signature = signature
|
self.signature = signature
|
||||||
}
|
}
|
||||||
|
|
||||||
init?(token: String) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
62
Jot/Token/TokenDeserializer.swift
Normal file
62
Jot/Token/TokenDeserializer.swift
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// TokenDeserializer.swift
|
||||||
|
// Jot
|
||||||
|
//
|
||||||
|
// Created by James Griffin-Allwood on 2018-12-29.
|
||||||
|
// Copyright © 2018 James Griffin-Allwood. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import os.log
|
||||||
|
|
||||||
|
extension JWT {
|
||||||
|
convenience init?(token: String) {
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
let jwtParts = token.split(separator: ".")
|
||||||
|
guard jwtParts.count == 3 else {
|
||||||
|
os_log("Invalid JWT format. Requires 3 parts", log: OSLog.default, type: .error)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let base64Header = String(jwtParts[0])
|
||||||
|
guard let headerData = Data(base64Encoded: base64Header.base64Pad()) else {
|
||||||
|
os_log("Header must be Base64 Encoded", log: OSLog.default, type: .error)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let base64Payload = String(jwtParts[1])
|
||||||
|
guard let payloadData = Data(base64Encoded: base64Payload.base64Pad()) else {
|
||||||
|
os_log("Payload must be Base64 Encoded", log: OSLog.default, type: .error)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Base64 Decoding the signature fails. Leave alone until adding Token Validation
|
||||||
|
// let base64Signature = String(jwtParts[2])
|
||||||
|
// guard let signatureData = Data(base64Encoded: base64Signature.base64Pad()) else {
|
||||||
|
// os_log("Signature must be Base64 Encoded", log: OSLog.default, type: .error)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
do {
|
||||||
|
let header = try decoder.decode(Header.self, from: headerData)
|
||||||
|
let payload = try decoder.decode(Payload.self, from: payloadData)
|
||||||
|
let signature = Signature()
|
||||||
|
self.init(header: header, payload: payload, signature: signature)
|
||||||
|
} catch {
|
||||||
|
os_log("Unable to deserialize JWT: %@", log: OSLog.default, type: .error, error.localizedDescription)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
func base64Pad() -> String {
|
||||||
|
var paddedString = self
|
||||||
|
if self.count % 4 != 0 {
|
||||||
|
let charactersToAdd = 4 - self.count % 4
|
||||||
|
paddedString.append(contentsOf: repeatElement("=", count: charactersToAdd))
|
||||||
|
}
|
||||||
|
return paddedString
|
||||||
|
}
|
||||||
|
}
|
@@ -10,13 +10,15 @@ import XCTest
|
|||||||
@testable import Jot
|
@testable import Jot
|
||||||
|
|
||||||
class JotTests: XCTestCase {
|
class JotTests: XCTestCase {
|
||||||
var jwt: JWT?
|
|
||||||
|
|
||||||
override func setUp() {
|
|
||||||
self.jwt = JWT(token: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqZ3JpZmZpbiIsIm5hbWUiOiJKYW1lcyBHcmlmZmluIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.DXfNW7Gzvie7LIl5-HSG9clm3sjeglYG2uNmsPvcNerBQbzLI06vys4YqqCMtrWKEFij_y2hKGP9YFdHSRMdtyVcGEXmYP6H6E62uGhASmGFzEHeSa6B1X1-v8lRt_YpIGEXhkUnxfhdcQ90HJlNfajv0ndnRFk8YJxRkmr99OI")
|
|
||||||
}
|
|
||||||
|
|
||||||
func testJWTInit() {
|
func testJWTInit() {
|
||||||
XCTAssertNotNil(self.jwt)
|
guard let jwt = JWT(token: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqZ3JpZmZpbiIsIm5hbWUiOiJKYW1lcyBHcmlmZmluIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.DXfNW7Gzvie7LIl5-HSG9clm3sjeglYG2uNmsPvcNerBQbzLI06vys4YqqCMtrWKEFij_y2hKGP9YFdHSRMdtyVcGEXmYP6H6E62uGhASmGFzEHeSa6B1X1-v8lRt_YpIGEXhkUnxfhdcQ90HJlNfajv0ndnRFk8YJxRkmr99OI") else {
|
||||||
|
XCTFail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertEqual(jwt.header.alg, SigningAlgorithm.rsa256)
|
||||||
|
XCTAssertEqual(jwt.header.typ, JwtType.jwt)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user