Skip to content

Commit

Permalink
feat: Make base64url Data utilities public (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
djones6 authored Sep 27, 2019
1 parent 45fdc4a commit 3d4e117
Show file tree
Hide file tree
Showing 59 changed files with 1,623 additions and 570 deletions.
4 changes: 2 additions & 2 deletions Sources/SwiftJWT/BlueECDSA.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class BlueECSigner: SignerAlgorithm {
throw JWTError.invalidJWTString
}
let signature = try sign(unsignedData)
let signatureString = signature.base64urlEncodedString()
let signatureString = JWTEncoder.base64urlEncodedString(data: signature)
return header + "." + claims + "." + signatureString
}

Expand Down Expand Up @@ -76,7 +76,7 @@ class BlueECVerifier: VerifierAlgorithm {
func verify(jwt: String) -> Bool {
let components = jwt.components(separatedBy: ".")
if components.count == 3 {
guard let signature = Data(base64urlEncoded: components[2]),
guard let signature = JWTDecoder.data(base64urlEncoded: components[2]),
let jwtData = (components[0] + "." + components[1]).data(using: .utf8)
else {
return false
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftJWT/BlueHMAC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class BlueHMAC: SignerAlgorithm, VerifierAlgorithm {
throw JWTError.invalidJWTString
}
let signature = try sign(unsignedData)
let signatureString = signature.base64urlEncodedString()
let signatureString = JWTEncoder.base64urlEncodedString(data: signature)
return header + "." + claims + "." + signatureString
}

Expand All @@ -58,7 +58,7 @@ class BlueHMAC: SignerAlgorithm, VerifierAlgorithm {
func verify(jwt: String) -> Bool {
let components = jwt.components(separatedBy: ".")
if components.count == 3 {
guard let signature = Data(base64urlEncoded: components[2]),
guard let signature = JWTDecoder.data(base64urlEncoded: components[2]),
let jwtData = (components[0] + "." + components[1]).data(using: .utf8)
else {
return false
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftJWT/BlueRSA.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class BlueRSA: SignerAlgorithm, VerifierAlgorithm {
throw JWTError.invalidJWTString
}
let signature = try sign(unsignedData)
let signatureString = signature.base64urlEncodedString()
let signatureString = JWTEncoder.base64urlEncodedString(data: signature)
return header + "." + claims + "." + signatureString
}

Expand Down Expand Up @@ -76,7 +76,7 @@ class BlueRSA: SignerAlgorithm, VerifierAlgorithm {
func verify(jwt: String) -> Bool {
let components = jwt.components(separatedBy: ".")
if components.count == 3 {
guard let signature = Data(base64urlEncoded: components[2]),
guard let signature = JWTDecoder.data(base64urlEncoded: components[2]),
let jwtData = (components[0] + "." + components[1]).data(using: .utf8)
else {
return false
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftJWT/Claims.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ public extension Claims {
let jsonEncoder = JSONEncoder()
jsonEncoder.dateEncodingStrategy = .secondsSince1970
let data = try jsonEncoder.encode(self)
return data.base64urlEncodedString()
return JWTEncoder.base64urlEncodedString(data: data)
}
}
25 changes: 19 additions & 6 deletions Sources/SwiftJWT/Data+Base64URLEncoded.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corporation 2017
* Copyright IBM Corporation 2017-2019
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,22 +16,35 @@

import Foundation

/// Convenience extension for encoding a `Data` as a base64url-encoded `String`.
extension JWTEncoder {

extension Data {
func base64urlEncodedString() -> String {
let result = self.base64EncodedString()
/// Returns a `String` representation of this data, encoded in base64url format
/// as defined in RFC4648 (https://tools.ietf.org/html/rfc4648).
///
/// This is the appropriate format for encoding the header and claims of a JWT.
public static func base64urlEncodedString(data: Data) -> String {
let result = data.base64EncodedString()
return result.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
}
}

/// Convenience extension for decoding a `Data` from a base64url-encoded `String`.
extension JWTDecoder {

init?(base64urlEncoded: String) {
/// Initializes a new `Data` from the base64url-encoded `String` provided. The
/// base64url encoding is defined in RFC4648 (https://tools.ietf.org/html/rfc4648).
///
/// This is appropriate for reading the header or claims portion of a JWT string.
public static func data(base64urlEncoded: String) -> Data? {
let paddingLength = 4 - base64urlEncoded.count % 4
let padding = (paddingLength < 4) ? String(repeating: "=", count: paddingLength) : ""
let base64EncodedString = base64urlEncoded
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
+ padding
self.init(base64Encoded: base64EncodedString)
return Data(base64Encoded: base64EncodedString)
}
}
2 changes: 1 addition & 1 deletion Sources/SwiftJWT/Header.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@ public struct Header: Codable {
let jsonEncoder = JSONEncoder()
jsonEncoder.dateEncodingStrategy = .secondsSince1970
let data = try jsonEncoder.encode(self)
return data.base64urlEncodedString()
return JWTEncoder.base64urlEncodedString(data: data)
}
}
4 changes: 2 additions & 2 deletions Sources/SwiftJWT/JWT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public struct JWT<T: Claims>: Codable {
public init(jwtString: String, verifier: JWTVerifier = .none ) throws {
let components = jwtString.components(separatedBy: ".")
guard components.count == 2 || components.count == 3,
let headerData = Data(base64urlEncoded: components[0]),
let claimsData = Data(base64urlEncoded: components[1])
let headerData = JWTDecoder.data(base64urlEncoded: components[0]),
let claimsData = JWTDecoder.data(base64urlEncoded: components[1])
else {
throw JWTError.invalidJWTString
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftJWT/JWTDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ public class JWTDecoder: BodyDecoder {
public func decode<T : Decodable>(_ type: T.Type, fromString: String) throws -> T {
// Seperate the JWT into the headers and claims.
let components = fromString.components(separatedBy: ".")
guard let headerData = Data(base64urlEncoded: components[0]),
let claimsData = Data(base64urlEncoded: components[1])
guard let headerData = JWTDecoder.data(base64urlEncoded: components[0]),
let claimsData = JWTDecoder.data(base64urlEncoded: components[1])
else {
throw JWTError.invalidJWTString
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftJWT/JWTEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ fileprivate class _JWTEncoder: Encoder {
}
_header.alg = encoder.jwtSigner?.name
let data = try jsonEncoder.encode(_header)
encoder.header = data.base64urlEncodedString()
encoder.header = JWTEncoder.base64urlEncodedString(data: data)
} else if fieldName == "claims" {
let data = try jsonEncoder.encode(value)
encoder.claims = data.base64urlEncodedString()
encoder.claims = JWTEncoder.base64urlEncodedString(data: data)
}
}

Expand Down
Loading

0 comments on commit 3d4e117

Please sign in to comment.